From b58bd5b311c4db41416235679a8da0b364c77996 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 4 Dec 2018 13:49:29 +0100 Subject: [PATCH 001/195] Version 1.67 WIP + todo notes --- docs/TODO.txt | 12 +++++++++--- imgui.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 2b760243..ec4f5c24 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -74,6 +74,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it. - input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position. - input text: what's the easiest way to implement a nice IP/Mac address input editor? + - input text: Global callback system so user can plug in an expression evaluator easily. - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: support for cut/paste without selection (cut/paste the current line) - input text multi-line: line numbers? status bar? (follow up on #200) @@ -253,8 +254,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - 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) - font: fix AddRemapChar() to work before font has been built. - - font: (api breaking) removed "TTF" from symbol names. also because it now supports OTF. + - font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF. + - font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer? + - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16 bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? + - nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window" - nav: wrap around logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). - nav: patterns to make it possible for arrows key to update selection - nav: restore/find nearest navid when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name) @@ -266,8 +270,10 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - nav: NavFlattened: init request doesn't select items that are part of a NavFlattened child - nav: NavFlattened: cannot access menu-bar of a flattened child window with Alt/menu key (not a very common use case..). - nav: Left within a tree node block as a fallback (ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default?) - - nav: menus: pressing left-right on a vertically clipped menu bar tends to jump to the collapse/close buttons. - - nav: menus: allow pressing Menu to leave a sub-menu. + - nav/menus: pressing left-right on a vertically clipped menu bar tends to jump to the collapse/close buttons. + - nav/menus: allow pressing Menu to leave a sub-menu. + - nav/menus: a way to access the main menu bar with Alt? (currently needs CTRL+TAB) + - nav/menus: when using the main menu bar, even though we restore focus after, the underlying window loses its title bar highlight during menu manipulation. could we prevent it? - nav: simulate right-click or context activation? (SHIFT+F10) - nav: tabs should go through most/all widgets (in submission order?). - nav: when CTRL-Tab/windowing is active, the HoveredWindow detection doesn't take account of the window display re-ordering. diff --git a/imgui.h b/imgui.h index 8e695c5f..effc60df 100644 --- a/imgui.h +++ b/imgui.h @@ -44,7 +44,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens) -#define IMGUI_VERSION "1.66b" +#define IMGUI_VERSION "1.67 WIP" #define IMGUI_VERSION_NUM 16602 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) From 125e62491eb29d4d91429ba7653a50714f9fe123 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 4 Dec 2018 14:30:11 +0100 Subject: [PATCH 002/195] Internals: Nav: Added ImGuiNavLayer_ to clarify semantic of previously integer NavLayer values, and not pretend that increment/decrement operators on them super flexible. + Storage tweaks. --- imgui.cpp | 42 +++++++++++++++++++++--------------------- imgui_internal.h | 43 +++++++++++++++++++++++++------------------ imgui_widgets.cpp | 10 +++++----- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 76e66d6e..38d8ab4b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2493,7 +2493,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) IM_ASSERT(id != 0); // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it. - const int nav_layer = window->DC.NavLayerCurrent; + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; if (g.NavWindow != window) g.NavInitRequest = false; g.NavId = id; @@ -4210,14 +4210,14 @@ static void CheckStacksSize(ImGuiWindow* window, bool write) { // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) ImGuiContext& g = *GImGui; - int* p_backup = &window->DC.StackSizesBackup[0]; - { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() - { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() - { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() + short* p_backup = &window->DC.StackSizesBackup[0]; + { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() + { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() + { int current = g.CurrentPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. - { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() - { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() - { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() + { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() + { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() + { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont() IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); } @@ -4695,7 +4695,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Active = true; window->BeginOrderWithinParent = 0; - window->BeginOrderWithinContext = g.WindowsActiveCount++; + window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); window->BeginCount = 0; window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); window->LastFrameActive = current_frame; @@ -4817,7 +4817,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Position child window if (flags & ImGuiWindowFlags_ChildWindow) { - window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size; + window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) window->Pos = parent_window->DC.CursorPos; @@ -5018,7 +5018,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.NavHideHighlightOneFrame = false; - window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f); + window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f); window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; window->DC.NavLayerActiveMaskNext = 0x00; window->DC.MenuBarAppending = false; @@ -5063,8 +5063,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags 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++; - window->DC.NavLayerCurrentMask <<= 1; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); // Collapse button if (!(flags & ImGuiWindowFlags_NoCollapse)) @@ -5080,8 +5080,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) *p_open = false; } - window->DC.NavLayerCurrent--; - window->DC.NavLayerCurrentMask >>= 1; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); window->DC.ItemFlags = item_flags_backup; // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.) @@ -5263,7 +5263,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) g.NavInitRequest = false; g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId g.NavIdIsAlive = false; - g.NavLayer = 0; + g.NavLayer = ImGuiNavLayer_Main; //printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL); } @@ -7062,7 +7062,7 @@ static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; } -static void NavRestoreLayer(int layer) +static void NavRestoreLayer(ImGuiNavLayer layer) { ImGuiContext& g = *GImGui; g.NavLayer = layer; @@ -7319,7 +7319,7 @@ static void ImGui::NavUpdate() else if (g.NavLayer != 0) { // Leave the "menu" layer - NavRestoreLayer(0); + NavRestoreLayer(ImGuiNavLayer_Main); } else { @@ -7701,8 +7701,8 @@ static void ImGui::NavUpdateWindowing() NavInitWindow(apply_focus_window, false); // If the window only has a menu layer, select it directly - if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1)) - g.NavLayer = 1; + if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; } if (apply_focus_window) g.NavWindowingTarget = NULL; @@ -7722,7 +7722,7 @@ static void ImGui::NavUpdateWindowing() } g.NavDisableHighlight = false; g.NavDisableMouseHover = true; - NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0); + NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main); } } diff --git a/imgui_internal.h b/imgui_internal.h index 0039d271..d55261ff 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -241,12 +241,12 @@ struct IMGUI_API ImPool // Types //----------------------------------------------------------------------------- -// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches) +// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) struct ImVec1 { - float x; - ImVec1() { x = 0.0f; } - ImVec1(float _x) { x = _x; } + float x; + ImVec1() { x = 0.0f; } + ImVec1(float _x) { x = _x; } }; enum ImGuiButtonFlags_ @@ -392,6 +392,13 @@ enum ImGuiNavForward ImGuiNavForward_ForwardActive }; +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, // Main scrolling layer + ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu) + ImGuiNavLayer_COUNT +}; + enum ImGuiPopupPositionPolicy { ImGuiPopupPositionPolicy_Default, @@ -741,7 +748,7 @@ struct ImGuiContext float NavWindowingTimer; float NavWindowingHighlightAlpha; bool NavWindowingToggleLayer; - int NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. + ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) @@ -872,7 +879,7 @@ struct ImGuiContext NavWindowingTarget = NavWindowingTargetAnim = NavWindowingList = NULL; NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; NavWindowingToggleLayer = false; - NavLayer = 0; + NavLayer = ImGuiNavLayer_Main; NavIdTabCounter = INT_MAX; NavIdIsAlive = false; NavMousePosDirty = false; @@ -961,12 +968,12 @@ struct IMGUI_API ImGuiWindowTempData ImGuiItemStatusFlags LastItemStatusFlags; ImRect LastItemRect; // Interaction rect ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) - bool NavHideHighlightOneFrame; - bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) - int NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) + ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping. int NavLayerActiveMask; // Which layer have been written to (result from previous frame) int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) + bool NavHideHighlightOneFrame; + bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) bool MenuBarAppending; // FIXME: Remove this ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. ImVector ChildWindows; @@ -982,7 +989,7 @@ struct IMGUI_API ImGuiWindowTempData ImVector ItemWidthStack; ImVector TextWrapPosStack; ImVectorGroupStack; - int StackSizesBackup[6]; // Store size of various stacks for asserting + short StackSizesBackup[6]; // Store size of various stacks for asserting ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) ImVec1 GroupOffset; @@ -1000,11 +1007,11 @@ struct IMGUI_API ImGuiWindowTempData LastItemId = 0; LastItemStatusFlags = 0; LastItemRect = LastItemDisplayRect = ImRect(); + NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; + NavLayerCurrent = ImGuiNavLayer_Main; + NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); NavHideHighlightOneFrame = false; NavHasScroll = false; - NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; - NavLayerCurrent = 0; - NavLayerCurrentMask = 1 << 0; MenuBarAppending = false; MenuBarOffset = ImVec2(0.0f, 0.0f); StateStorage = NULL; @@ -1052,9 +1059,9 @@ struct IMGUI_API ImGuiWindow bool Appearing; // Set during the frame where the window is appearing (or re-appearing) bool Hidden; // Do not display (== (HiddenFramesForResize > 0) || bool HasCloseButton; // Set when the window has a close button (p_open != NULL) - int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) - int BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. - int BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. + short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) + short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) int AutoFitFramesX, AutoFitFramesY; bool AutoFitOnlyGrows; @@ -1090,8 +1097,8 @@ struct IMGUI_API ImGuiWindow ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) - ImGuiID NavLastIds[2]; // Last known NavId for this window, per layer (0/1) - ImRect NavRectRel[2]; // Reference rectangle, in window relative space + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) + ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space // Navigation / Focus // FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 792d80f0..d86fcaec 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5493,8 +5493,8 @@ bool ImGui::BeginMenuBar() window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; - window->DC.NavLayerCurrent++; - window->DC.NavLayerCurrentMask <<= 1; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); window->DC.MenuBarAppending = true; AlignTextToFramePadding(); return true; @@ -5520,7 +5520,7 @@ void ImGui::EndMenuBar() IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check FocusWindow(window); SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]); - g.NavLayer = 1; + g.NavLayer = ImGuiNavLayer_Menu; g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; NavMoveRequestCancel(); @@ -5535,8 +5535,8 @@ void ImGui::EndMenuBar() window->DC.GroupStack.back().AdvanceCursor = false; EndGroup(); // Restore position on layer 0 window->DC.LayoutType = ImGuiLayoutType_Vertical; - window->DC.NavLayerCurrent--; - window->DC.NavLayerCurrentMask >>= 1; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); window->DC.MenuBarAppending = false; } From b94f0241f1218d7a4caaa62e7a37e3cb825ea172 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Dec 2018 21:19:42 +0100 Subject: [PATCH 003/195] Docking: Adjusting the docking popup menu position so it tends to stay within the same viewport. --- imgui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3c9fcff6..d1651cf3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10845,8 +10845,8 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) DockNodeGetHostWindowTitle(node, window_label, IM_ARRAYSIZE(window_label)); ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_DockNodeHost; window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; - window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; - window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoTitleBar; PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); Begin(window_label, NULL, window_flags); @@ -11032,7 +11032,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w // Collapse button changes shape and display a list if (IsPopupOpen("#TabListMenu")) { - SetNextWindowPos(ImVec2(node->Pos.x - style.FramePadding.x, node->Pos.y + GetFrameHeight())); + // Try to position the menu so it is more likely to stays within the same viewport + SetNextWindowPos(ImVec2(node->Pos.x, node->Pos.y + GetFrameHeight())); if (BeginPopup("#TabListMenu")) { is_focused = true; From e2082a675c209b3135eae4abcc0f4413662965e7 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Dec 2018 23:38:37 +0100 Subject: [PATCH 004/195] Viewport: Fix handling of PlatformRequestResize/PlatformRequestPos. when OS decoration are enabled via ImGuiConfigFlags_ViewportsDecoration . --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d1651cf3..5110b07a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7687,8 +7687,10 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id); if (viewport) { - viewport->Pos = pos; - viewport->Size = size; + if (!viewport->PlatformRequestMove) + viewport->Pos = pos; + if (!viewport->PlatformRequestResize) + viewport->Size = size; } else { From ac52d9d44c0d8aeac198cec513a2ff25dda97394 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 5 Dec 2018 23:38:37 +0100 Subject: [PATCH 005/195] Viewport: Fix handling of PlatformRequestResize/PlatformRequestPos. when OS decoration are enabled via ImGuiConfigFlags_ViewportsDecoration . --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 149d7828..0c42cfb1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7435,8 +7435,10 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id); if (viewport) { - viewport->Pos = pos; - viewport->Size = size; + if (!viewport->PlatformRequestMove) + viewport->Pos = pos; + if (!viewport->PlatformRequestResize) + viewport->Size = size; } else { From f3a0b17bb8be22c8ae88a6a064c25c1cf13c3c72 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 6 Dec 2018 16:30:10 +0100 Subject: [PATCH 006/195] Viewport: Win32, GLFW, SDL: Clarified back-ends by using global mouse position direction. GLFW: disabled io.MouseHoveredViewport setting under Mac/Linux. (#1542, #2117) + various comments. --- examples/imgui_impl_glfw.cpp | 26 +++++++++++++++--- examples/imgui_impl_sdl.cpp | 22 ++++++++------- examples/imgui_impl_win32.cpp | 51 +++++++++++++++++++++-------------- imgui.h | 2 +- 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 2c4c9cb6..a327669a 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -141,7 +141,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) -#if GLFW_HAS_GLFW_HOVERED +#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32) io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy) #endif io.BackendPlatformName = "imgui_impl_glfw"; @@ -264,14 +264,32 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons() { double mouse_x, mouse_y; glfwGetCursorPos(window, &mouse_x, &mouse_y); - io.MousePos = ImVec2((float)mouse_x + viewport->Pos.x, (float)mouse_y + viewport->Pos.y); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) + int window_x, window_y; + glfwGetWindowPos(window, &window_x, &window_y); + io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y); + } + else + { + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + } } for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0; } -#if GLFW_HAS_GLFW_HOVERED - io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; + // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering. + // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because + // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows). + // - This is _regardless_ of whether another viewport is focused or being dragged from. + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the + // rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows. + // [GLFW] FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems. + // See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature. +#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32) if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !(viewport->Flags & ImGuiViewportFlags_NoInputs)) io.MouseHoveredViewport = viewport->ID; #endif diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 7ef8dec0..3e883550 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -264,16 +264,20 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons() SDL_Window* focused_window = SDL_GetKeyboardFocus(); if (focused_window) { - // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?) - // The creation of new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally. - int wx, wy; - SDL_GetWindowPosition(focused_window, &wx, &wy); - SDL_GetGlobalMouseState(&mx, &my); - mx -= wx; - my -= wy; + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) + SDL_GetGlobalMouseState(&mx, &my); + if (ImGui::FindViewportByPlatformHandle((void*)focused_window) != NULL) + io.MousePos = ImVec2((float)mx, (float)my); + } + else + { + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) + if (focused_window == g_Window) + io.MousePos = ImVec2((float)mx, (float)my); + } } - if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)focused_window)) - io.MousePos = ImVec2(viewport->Pos.x + (float)mx, viewport->Pos.y + (float)my); // We already retrieve global mouse position, SDL_CaptureMouse() also let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't trigger the OS window resize cursor // The function is only supported from SDL 2.0.4 (released Jan 2016) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 932bc211..63c27046 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -135,21 +135,14 @@ static bool ImGui_ImplWin32_UpdateMouseCursor() return true; } -// This code supports multiple OS Windows mapped into different ImGui viewports, -// Because of that, it is a little more complicated than your typical single-viewport binding code. -// A) In Single-viewport mode imgui needs: -// - io.MousePos ............... mouse position, in client window coordinates (what you'd get from GetCursorPos+ScreenToClient() or from WM_MOUSEMOVE) -// io.MousePos is (0,0) when the mouse is on the upper-left corner of the application window. -// B) In Multi-viewport mode imgui needs: (when ImGuiConfigFlags_ViewportsEnable is set) -// - io.MousePos ............... mouse position, in OS absolute coordinates (what you'd get from GetCursorPos(), or from WM_MOUSEMOVE+viewport->Pos). -// io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor. -// - io.MouseHoveredViewport ... [optional] viewport which mouse is hovering, with _VERY_ specific and strict conditions (Read comments next to io.MouseHoveredViewport. This is _NOT_ easy to provide in many high-level engine because of how we use the ImGuiViewportFlags_NoInputs flag) +// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports) +// Because of that, it is a little more complicated than your typical single-viewport binding code! static void ImGui_ImplWin32_UpdateMousePos() { ImGuiIO& io = ImGui::GetIO(); // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - // (When multi-viewports are enabled, all imgui positions are same as OS positions.) + // (When multi-viewports are enabled, all imgui positions are same as OS positions) if (io.WantSetMousePos) { POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; @@ -161,21 +154,39 @@ static void ImGui_ImplWin32_UpdateMousePos() io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); io.MouseHoveredViewport = 0; - // Set mouse position and viewport - // (Note that ScreenToClient() and adding +viewport->Pos are mutually cancelling each others when we have multi-viewport enabled. In single-viewport mode, viewport->Pos will be zero) - POINT pos; - if (!::GetCursorPos(&pos)) + // Set imgui mouse position + POINT mouse_screen_pos; + if (!::GetCursorPos(&mouse_screen_pos)) return; if (HWND focused_hwnd = ::GetActiveWindow()) - if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)focused_hwnd)) + { + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) + // This is the position you can get with GetCursorPos(). In theory adding viewport->Pos is also the reverse operation of doing ScreenToClient(). + if (ImGui::FindViewportByPlatformHandle((void*)focused_hwnd) != NULL) + io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y); + } + else { - POINT client_pos = pos; - ::ScreenToClient(focused_hwnd, &client_pos); - io.MousePos = ImVec2(viewport->Pos.x + (float)client_pos.x, viewport->Pos.y + (float)client_pos.y); + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window.) + // This is the position you can get with GetCursorPos() + ScreenToClient() or from WM_MOUSEMOVE. + if (focused_hwnd == g_hWnd) + { + POINT mouse_client_pos = mouse_screen_pos; + ::ScreenToClient(focused_hwnd, &mouse_client_pos); + io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y); + } } + } - // Our back-end can tell which window is under the mouse cursor (not every back-end can), so pass that info to imgui - if (HWND hovered_hwnd = ::WindowFromPoint(pos)) + // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering. + // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because + // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows). + // - This is _regardless_ of whether another viewport is focused or being dragged from. + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the + // rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows. + if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd)) io.MouseHoveredViewport = viewport->ID; } diff --git a/imgui.h b/imgui.h index 4a6e435b..ca4326e9 100644 --- a/imgui.h +++ b/imgui.h @@ -1231,7 +1231,7 @@ struct ImGuiIO bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends. - ImGuiID MouseHoveredViewport; // (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will use a decent heuristic instead. + ImGuiID MouseHoveredViewport; // (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). bool KeyCtrl; // Keyboard modifier pressed: Control bool KeyShift; // Keyboard modifier pressed: Shift bool KeyAlt; // Keyboard modifier pressed: Alt From 3a5e758ee37582a52360ada72219d5162ddd3268 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 8 Dec 2018 12:35:15 +0100 Subject: [PATCH 007/195] Tabs: Fixed crash when using TabItem in a regular (non-docking) tab bar. (#2231) --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b0a0c68f..086550a8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6455,8 +6455,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Drag and drop a single floating window node moves it // FIXME-DOCK: In theory we shouldn't test for the ConfigDockingNodifySingleWindows flag here. // When our single window node and OnlyNodeWithWindows are working properly we may remove this check here. - ImGuiDockNode* node = docked_window->DockNode; - const bool single_window_node = node->IsRootNode() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; + ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL; + const bool single_window_node = node && node->IsRootNode() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; if (held && single_window_node && IsMouseDragging(0, 0.0f)) { // Move From d20e3ee710c46cb8053f1d82864c1ba6792ff738 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 6 Dec 2018 18:18:54 +0100 Subject: [PATCH 008/195] Tests: Adding imgui-test engine hooks (experimental) to provide missing widget state to the testing system. --- imgui.cpp | 20 ++++++-------------- imgui_internal.h | 20 ++++++++++++++++++++ imgui_widgets.cpp | 14 +++++++++++--- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 38d8ab4b..cd8d7f92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -957,14 +957,6 @@ 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]); } -// Test engine hooks (imgui-test) -//#define IMGUI_ENABLE_TEST_ENGINE_HOOKS -#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS -extern void ImGuiTestEngineHook_PreNewFrame(); -extern void ImGuiTestEngineHook_PostNewFrame(); -extern void ImGuiTestEngineHook_ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg); -#endif - //----------------------------------------------------------------------------- // [SECTION] CONTEXT AND MEMORY ALLOCATORS //----------------------------------------------------------------------------- @@ -2607,10 +2599,6 @@ void ImGui::ItemSize(const ImRect& bb, float text_offset_y) // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) { -#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS - ImGuiTestEngineHook_ItemAdd(bb, id, nav_bb_arg); -#endif - ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -2632,6 +2620,10 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemRect = bb; window->DC.LastItemStatusFlags = 0; +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiTestEngineHook_ItemAdd(id, bb); +#endif + // Clipping test const bool is_clipped = IsClippedEx(bb, id, false); if (is_clipped) @@ -3130,7 +3122,7 @@ void ImGui::NewFrame() IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); ImGuiContext& g = *GImGui; -#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS +#ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_PreNewFrame(); #endif @@ -3305,7 +3297,7 @@ void ImGui::NewFrame() SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); Begin("Debug##Default"); -#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS +#ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_PostNewFrame(); #endif } diff --git a/imgui_internal.h b/imgui_internal.h index d55261ff..167f7c4e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -314,6 +314,14 @@ enum ImGuiItemStatusFlags_ ImGuiItemStatusFlags_HoveredRect = 1 << 0, ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, ImGuiItemStatusFlags_Edited = 1 << 2 // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) + +#ifdef IMGUI_ENABLE_TEST_ENGINE + , // [imgui-test only] + ImGuiItemStatusFlags_Openable = 1 << 10, // + ImGuiItemStatusFlags_Opened = 1 << 11, // + ImGuiItemStatusFlags_Checkable = 1 << 12, // + ImGuiItemStatusFlags_Checked = 1 << 13 // +#endif }; // FIXME: this is in development, not exposed/functional as a generic feature yet. @@ -1329,6 +1337,18 @@ IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); 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); +// Test engine hooks (imgui-test) +//#define IMGUI_ENABLE_TEST_ENGINE +#ifdef IMGUI_ENABLE_TEST_ENGINE +extern void ImGuiTestEngineHook_PreNewFrame(); +extern void ImGuiTestEngineHook_PostNewFrame(); +extern void ImGuiTestEngineHook_ItemAdd(ImGuiID id, const ImRect& bb); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiID id, const char* label, int flags); +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(_ID, _LABEL, _FLAGS) // Register status flags +#else +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) +#endif + #ifdef __clang__ #pragma clang diagnostic pop #endif diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d86fcaec..ab553661 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -913,6 +913,7 @@ bool ImGui::Checkbox(const char* label, bool* v) if (label_size.x > 0.0f) RenderText(text_bb.Min, label); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } @@ -4760,6 +4761,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not) const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y); bool is_open = TreeNodeBehaviorIsOpen(id, flags); + bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). @@ -4775,6 +4777,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushRawID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -4784,13 +4787,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // - OpenOnArrow .................... single-click on arrow to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0); - if (!(flags & ImGuiTreeNodeFlags_Leaf)) + if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); - if (!(flags & ImGuiTreeNodeFlags_Leaf)) + if (!is_leaf) { bool toggled = false; if (pressed) @@ -4858,7 +4861,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); - else if (!(flags & ImGuiTreeNodeFlags_Leaf)) + else if (!is_leaf) RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); if (g.LogEnabled) LogRenderedText(&text_pos, ">"); @@ -4867,6 +4870,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushRawID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -5650,6 +5654,8 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (want_close && IsPopupOpen(id)) ClosePopupToLevel(g.CurrentPopupStack.Size); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size) { // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. @@ -5729,6 +5735,8 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo if (selected) RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); } + + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); return pressed; } From 59f3c4fc20c87d26e7968961eaaf9a7f89442beb Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 10 Dec 2018 15:36:07 +0100 Subject: [PATCH 009/195] Renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges and removed its [Beta] mark. Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. --- docs/CHANGELOG.txt | 5 +++++ imgui.cpp | 41 +++++++++++++++++++++-------------------- imgui.h | 10 +++++----- imgui_demo.cpp | 34 ++++++++++++++++------------------ 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7ca7f6b8..aae96f29 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,9 +35,14 @@ HOW TO UPDATE? Breaking Changes: +- Renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges and removed its [Beta] mark. + The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. + Other Changes: - Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file to ease integration. +- Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that + it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index cd8d7f92..3e7cbb2f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -345,7 +345,8 @@ 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. - - 2018/10/12 (1.66) - Renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. + - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. + - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. @@ -356,7 +357,7 @@ CODE - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). - - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges to enable the feature. + - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature. - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). @@ -902,9 +903,9 @@ CODE static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear -// Window resizing from edges (when io.ConfigResizeWindowsFromEdges = true) -static const float RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). -static const float RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. +// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end) +static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). +static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. //------------------------------------------------------------------------- // [SECTION] FORWARD DECLARATIONS @@ -1086,7 +1087,7 @@ ImGuiIO::ImGuiIO() ConfigMacOSXBehaviors = false; #endif ConfigInputTextCursorBlink = true; - ConfigResizeWindowsFromEdges = false; + ConfigWindowsResizeFromEdges = true; // Platform Functions BackendPlatformName = BackendRendererName = NULL; @@ -3143,9 +3144,9 @@ void ImGui::NewFrame() if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); - // Perform simple check: the beta io.ConfigResizeWindowsFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. - if (g.IO.ConfigResizeWindowsFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) - g.IO.ConfigResizeWindowsFromEdges = false; + // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; // Load settings on first frame (if not explicitly loaded manually before) if (!g.SettingsLoaded) @@ -3753,8 +3754,8 @@ static void FindHoveredWindow() hovered_window = g.MovingWindow; ImVec2 padding_regular = g.Style.TouchExtraPadding; - ImVec2 padding_for_resize_from_edges = g.IO.ConfigResizeWindowsFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS)) : padding_regular; - for (int i = g.Windows.Size - 1; i >= 0 && hovered_window == NULL; i--) + ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; + for (int i = g.Windows.Size - 1; i >= 0; i--) { ImGuiWindow* window = g.Windows[i]; if (!window->Active || window->Hidden) @@ -4451,10 +4452,10 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. return; - const int resize_border_count = g.IO.ConfigResizeWindowsFromEdges ? 4 : 0; + const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f); const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f); - const float grip_hover_outer_size = g.IO.ConfigResizeWindowsFromEdges ? RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS : 0.0f; + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; ImVec2 pos_target(FLT_MAX, FLT_MAX); ImVec2 size_target(FLT_MAX, FLT_MAX); @@ -4495,10 +4496,10 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au for (int border_n = 0; border_n < resize_border_count; border_n++) { bool hovered, held; - ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren); //GetOverlayDrawList(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); - if ((hovered && g.HoveredIdTimer > RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER) || held) + if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) { g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; if (held) *border_held = border_n; @@ -4507,10 +4508,10 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au { ImVec2 border_target = window->Pos; ImVec2 border_posn; - if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); } } @@ -4859,7 +4860,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Handle manual resize: Resize Grips, Borders, Gamepad int border_held = -1; ImU32 resize_grip_col[4] = { 0 }; - const int resize_grip_count = g.IO.ConfigResizeWindowsFromEdges ? 2 : 1; // 4 + 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); if (!window->Collapsed) UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); diff --git a/imgui.h b/imgui.h index effc60df..06dfe96f 100644 --- a/imgui.h +++ b/imgui.h @@ -679,7 +679,7 @@ enum ImGuiWindowFlags_ // [Obsolete] //ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f / style.WindowBorderSize=1.0f to enable borders around windows and items - //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigResizeWindowsFromEdges and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) + //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) }; // Flags for ImGui::InputText() @@ -1162,10 +1162,10 @@ struct ImGuiIO ImVec2 DisplayVisibleMax; // (0.0f,0.0f) // [OBSOLETE: just use io.DisplaySize!] If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize // Miscellaneous configuration options - bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. - bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) - bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) - bool ConfigResizeWindowsFromEdges; // = false // [BETA] Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the ImGuiWindowFlags_ResizeFromAnySide flag) + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) + bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) //------------------------------------------------------------------ // Platform Functions diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1571bda1..937bd410 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -316,7 +316,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); - ImGui::Checkbox("io.ConfigResizeWindowsFromEdges [beta]", &io.ConfigResizeWindowsFromEdges); + ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); ImGui::SameLine(); ShowHelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); ImGui::SameLine(); ShowHelpMarker("Instruct Dear ImGui to render a mouse cursor for you. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); @@ -2532,25 +2532,23 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::Text("define: __clang_version__=%s", __clang_version__); #endif ImGui::Separator(); - ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); - if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); - if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); - if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); - if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); - if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); - if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); - if (io.ConfigFlags & ImGuiConfigFlags_IsSRGB) ImGui::Text(" IsSRGB"); - if (io.ConfigFlags & ImGuiConfigFlags_IsTouchScreen) ImGui::Text(" IsTouchScreen"); - if (io.MouseDrawCursor) ImGui::Text(" MouseDrawCursor"); - if (io.ConfigMacOSXBehaviors) ImGui::Text(" ConfigMacOSXBehaviors"); - if (io.ConfigInputTextCursorBlink) ImGui::Text(" ConfigInputTextCursorBlink"); - if (io.ConfigResizeWindowsFromEdges) ImGui::Text(" ConfigResizeWindowsFromEdges"); - ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); - if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); - if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); - if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); + ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); + if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); + if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); + if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); + if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); + if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); + ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); + if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); + if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); + if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); ImGui::Separator(); ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); From 9476e07d5ac2f03771800a10db87a1494c0138f9 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 10 Dec 2018 16:05:30 +0100 Subject: [PATCH 010/195] Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. --- docs/CHANGELOG.txt | 8 ++++++-- imgui.cpp | 15 +++++++++++++-- imgui.h | 1 + imgui_demo.cpp | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index aae96f29..65af0afd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,10 +39,14 @@ Breaking Changes: The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. Other Changes: -- Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file - to ease integration. - Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. +- Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). + This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) +- Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value + which is the same as the title bar height. +- Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file + to ease integration. ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 3e7cbb2f..54e81536 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1016,7 +1016,7 @@ ImGuiStyle::ImGuiStyle() GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. - DisplayWindowPadding = ImVec2(20,20); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. + DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. @@ -1088,6 +1088,7 @@ ImGuiIO::ImGuiIO() #endif ConfigInputTextCursorBlink = true; ConfigWindowsResizeFromEdges = true; + ConfigWindowsMoveFromTitleBarOnly = false; // Platform Functions BackendPlatformName = BackendRendererName = NULL; @@ -2906,6 +2907,8 @@ ImDrawListSharedData* ImGui::GetDrawListSharedData() void ImGui::StartMouseMovingWindow(ImGuiWindow* window) { // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. + // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. + // This is because we want ActiveId to be set even when the window is stuck from moving. ImGuiContext& g = *GImGui; FocusWindow(window); SetActiveID(window->MoveId, window); @@ -3571,9 +3574,16 @@ void ImGui::EndFrame() if (g.IO.MouseClicked[0]) { if (g.HoveredRootWindow != NULL) + { StartMouseMovingWindow(g.HoveredWindow); + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + } else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) + { FocusWindow(NULL); // Clicking on void disable focus + } } // With right mouse button we close popups without changing focus @@ -4832,7 +4842,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (!window_pos_set_by_api && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. { ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); - window->Pos = ImMax(window->Pos + window->Size, padding) - window->Size; + ImVec2 size_for_clamping = ((g.IO.ConfigWindowsMoveFromTitleBarOnly) && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size; + window->Pos = ImMax(window->Pos + size_for_clamping, padding) - size_for_clamping; window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding); } } diff --git a/imgui.h b/imgui.h index 06dfe96f..9b430669 100644 --- a/imgui.h +++ b/imgui.h @@ -1166,6 +1166,7 @@ struct ImGuiIO bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly;// = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. //------------------------------------------------------------------ // Platform Functions diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 937bd410..8b90df16 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -318,6 +318,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); ImGui::SameLine(); ShowHelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); + ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); ImGui::SameLine(); ShowHelpMarker("Instruct Dear ImGui to render a mouse cursor for you. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); ImGui::TreePop(); @@ -2545,6 +2546,7 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); + if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); From 2d4018aa893bf93b5b97a7aad5956fb3adbd866d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 11:03:28 +0100 Subject: [PATCH 011/195] Docking: Fix io.ConfigWindowsMoveFromTitleBarOnly for docking branch. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 875c8352..e3456a0a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3830,7 +3830,7 @@ void ImGui::EndFrame() if (g.HoveredRootWindow != NULL) { StartMouseMovingWindow(g.HoveredWindow); - if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && (!(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar) || g.HoveredWindow->RootWindowDockStop->DockIsActive)) if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) g.MovingWindow = NULL; } From 15447f5b7b5cd1e0bbfab2482100d266714f0bd5 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 11:58:15 +0100 Subject: [PATCH 012/195] Using named flags instead of 0 + shallow formatting tweaks from other branches. --- imgui.cpp | 49 +++++++++++++++++++++++++++++++++-------------- imgui.h | 2 +- imgui_internal.h | 6 ++++++ imgui_widgets.cpp | 2 -- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 54e81536..9ef1c638 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2328,7 +2328,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) Name = ImStrdup(name); ID = ImHash(name, 0); IDStack.push_back(ID); - Flags = 0; + Flags = ImGuiWindowFlags_None; Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f); @@ -2620,7 +2620,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemId = id; window->DC.LastItemRect = bb; - window->DC.LastItemStatusFlags = 0; + window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_ItemAdd(id, bb); @@ -4017,7 +4017,8 @@ bool ImGui::IsItemDeactivatedAfterEdit() bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; - return g.NavId && !g.NavDisableHighlight && g.NavId == g.CurrentWindow->DC.LastItemId; + ImGuiWindow* window = g.CurrentWindow; + return g.NavId && !g.NavDisableHighlight && g.NavId == window->DC.LastItemId; } bool ImGui::IsItemClicked(int mouse_button) @@ -4607,6 +4608,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const int current_frame = g.FrameCount; const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); + + // Update Flags, LastFrameActive, BeginOrderXXX fields if (first_begin_of_the_frame) window->Flags = (ImGuiWindowFlags)flags; else @@ -4940,9 +4943,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) g.NextWindowData.BgAlphaCond = 0; // Title bar - ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : 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) @@ -5166,7 +5171,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->HiddenFramesRegular = 1; // Update the Hidden flag - window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize); + window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize > 0); // Return false if we don't intend to display anything to allow user to perform an early out optimization window->SkipItems = (window->Collapsed || !window->Active || window->Hidden) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesForResize <= 0; @@ -6574,7 +6579,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values return false; } - return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); } bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) @@ -6593,7 +6599,8 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla if (g.NextWindowData.PosCond == 0) SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - bool is_open = Begin(name, p_open, flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings); + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; + const bool is_open = Begin(name, p_open, flags); if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) { EndPopup(); @@ -6756,6 +6763,12 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) return window->Pos; } +//----------------------------------------------------------------------------- +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +//----------------------------------------------------------------------------- + +// (this section is filled in the 'viewport' and 'docking' branches) + //----------------------------------------------------------------------------- // [SECTION] KEYBOARD/GAMEPAD NAVIGATION //----------------------------------------------------------------------------- @@ -6857,7 +6870,7 @@ static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max)) { ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); - ImDrawList* draw_list = GetOverlayDrawList(window); + ImDrawList* draw_list = ImGui::GetOverlayDrawList(window); draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150)); @@ -6869,7 +6882,7 @@ static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) if (quadrant == g.NavMoveDir) { ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); - ImDrawList* draw_list = GetOverlayDrawList(window); + ImDrawList* draw_list = ImGui::GetOverlayDrawList(window); draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); } @@ -7173,7 +7186,7 @@ ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect) { ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1)); - //g.OverlayDrawList.AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] + //GetOverlayDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] if (window_rect.Contains(item_rect)) return; @@ -7365,7 +7378,7 @@ static void ImGui::NavUpdate() if (g.NavMoveRequestForward == ImGuiNavForward_None) { g.NavMoveDir = ImGuiDir_None; - g.NavMoveRequestFlags = 0; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { if ((allowed_dir_flags & (1<DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 + && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 + && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) new_nav_window = new_nav_window->ParentWindow; if (new_nav_window != g.NavWindow) { @@ -8101,7 +8116,7 @@ void ImGui::ClearDragDrop() ImGuiContext& g = *GImGui; g.DragDropActive = false; g.DragDropPayload.Clear(); - g.DragDropAcceptFlags = 0; + g.DragDropAcceptFlags = ImGuiDragDropFlags_None; g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; g.DragDropAcceptIdCurrRectSurface = FLT_MAX; g.DragDropAcceptFrameCount = -1; @@ -8385,6 +8400,12 @@ void ImGui::EndDragDropTarget() g.DragDropWithinSourceOrTarget = false; } +//----------------------------------------------------------------------------- +// [SECTION] DOCKING +//----------------------------------------------------------------------------- + +// (this section is filled in the 'docking' branch) + //----------------------------------------------------------------------------- // [SECTION] LOGGING/CAPTURING //----------------------------------------------------------------------------- @@ -8892,6 +8913,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::End(); return; } + static bool show_draw_cmd_clip_rects = true; static bool show_window_begin_order = false; ImGuiIO& io = ImGui::GetIO(); @@ -8902,7 +8924,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Text("%d allocations", io.MetricsActiveAllocations); ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_draw_cmd_clip_rects); ImGui::Checkbox("Ctrl shows window begin order", &show_window_begin_order); - ImGui::Separator(); struct Funcs diff --git a/imgui.h b/imgui.h index 9b430669..fb3f7c4f 100644 --- a/imgui.h +++ b/imgui.h @@ -537,7 +537,7 @@ namespace ImGui IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) // Drag and Drop - // [BETA API] Missing Demo code. API may evolve. + // [BETA API] Missing Demo code. API may evolve! IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t size, ImGuiCond cond = 0);// type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! diff --git a/imgui_internal.h b/imgui_internal.h index 167f7c4e..c1d0016d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -679,7 +679,10 @@ struct ImGuiNextWindowData } }; +//----------------------------------------------------------------------------- // Main imgui context +//----------------------------------------------------------------------------- + struct ImGuiContext { bool Initialized; @@ -813,6 +816,8 @@ struct ImGuiContext ImVec2 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 + + // Platform support ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor // Settings @@ -1178,6 +1183,7 @@ namespace ImGui IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window); IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window); IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); + IMGUI_API void SetCurrentFont(ImFont* font); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ab553661..126fcf31 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1240,7 +1240,6 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float return held; } - //------------------------------------------------------------------------- // [SECTION] Widgets: ComboBox //------------------------------------------------------------------------- @@ -2627,7 +2626,6 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c return false; } -// NB: format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument) bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); From cc1283fb78a99979eebe61ea51fd0b63e9620c09 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 12:20:48 +0100 Subject: [PATCH 013/195] Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience to avoid using the ### operator. (merged from Docking branch) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 13 +++++++++++-- imgui.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 65af0afd..b969e441 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,8 @@ Breaking Changes: The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. Other Changes: +- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering + the ID, as a convenience to avoid using the ### operator. - Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. - Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). diff --git a/imgui.cpp b/imgui.cpp index 9ef1c638..5df233a7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5093,8 +5093,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); window->DC.ItemFlags = item_flags_backup; - // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.) - ImVec2 text_size = CalcTextSize(name, NULL, true); + // 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); @@ -5105,6 +5108,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) 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); + } } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() diff --git a/imgui.h b/imgui.h index fb3f7c4f..0d8f1964 100644 --- a/imgui.h +++ b/imgui.h @@ -665,6 +665,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker. ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, From 54a60aaa4017bde84d2945398d9bd4d2ebd5c978 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 12:36:47 +0100 Subject: [PATCH 014/195] Added BETA api for Tab Bar/Tabs widgets. (#261, #351) (merged this feature from the from Docking branch so it can be used earlier as as standalone feature) - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. - Added ImGuiTabBarFlags flags for BeginTabBar(). - Added ImGuiTabItemFlags flags for BeginTabItem(). - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. - Demo: Added Layout->Tabs demo code. - Demo: Added "Documents" example app showcasing possible use for tabs. --- docs/CHANGELOG.txt | 9 + docs/TODO.txt | 3 +- imgui.cpp | 68 +++- imgui.h | 43 +++ imgui_demo.cpp | 342 ++++++++++++++++++++ imgui_draw.cpp | 25 ++ imgui_internal.h | 79 +++++ imgui_widgets.cpp | 790 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1345 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b969e441..3ecb60ec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,15 @@ Breaking Changes: The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. Other Changes: +- Added BETA api for Tab Bar/Tabs widgets: (#261, #351) + - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. + - Added ImGuiTabBarFlags flags for BeginTabBar(). + - Added ImGuiTabItemFlags flags for BeginTabItem(). + - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. + - Demo: Added Layout->Tabs demo code. + - Demo: Added "Documents" example app showcasing possible use for tabs. + This feature was merged from the Docking branch in order to allow the use of regular tabs in your code. + (It does not provide the docking/splitting/merging of windows available in the Docking branch) - Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience to avoid using the ### operator. - Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that diff --git a/docs/TODO.txt b/docs/TODO.txt index ec4f5c24..bcd2fb11 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -127,7 +127,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: docking extension - dock: dock out from a collapsing header? would work nicely but need emitting window to keep submitting the code. - - tabs: re-ordering, close buttons, context menu, persistent order (#261, #351) + - tabs: make EndTabBar fail if users doesn't respect BeginTabBar return value, for consistency/future-proofing. + - tabs: persistent order/focus in BeginTabBar() api (#261, #351) - ext: stl-ish friendly extension (imgui_stl.h) that has wrapper for std::string, std::vector etc. diff --git a/imgui.cpp b/imgui.cpp index 5df233a7..99feb1b5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1015,6 +1015,8 @@ ImGuiStyle::ImGuiStyle() ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabBorderSize = 0.0f; // Thickness of border around tabs. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. @@ -1038,6 +1040,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -2160,17 +2163,8 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end // Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) { - // Hide anything after a '##' string - const char* text_display_end = FindRenderedTextEnd(text, text_end); - const int text_len = (int)(text_display_end - text); - if (text_len == 0) - return; - - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - // Perform CPU side clipping for single clipped element to avoid using scissor state ImVec2 pos = pos_min; const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); @@ -2189,14 +2183,27 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons if (need_clipping) { ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); - window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); } else { - window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); } +} + +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Hide anything after a '##' string + const char* text_display_end = FindRenderedTextEnd(text, text_end); + const int text_len = (int)(text_display_end - text); + if (text_len == 0) + return; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); if (g.LogEnabled) - LogRenderedText(&pos, text, text_display_end); + LogRenderedText(&pos_min, text, text_display_end); } // Render a rectangle shaped with optional rounding and borders @@ -5511,6 +5518,7 @@ static const ImGuiStyleVarInfo GStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign }; @@ -5603,6 +5611,11 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_ResizeGrip: return "ResizeGrip"; case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_Tab: return "Tab"; + case ImGuiCol_TabHovered: return "TabHovered"; + case ImGuiCol_TabActive: return "TabActive"; + case ImGuiCol_TabUnfocused: return "TabUnfocused"; + case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; case ImGuiCol_PlotLines: return "PlotLines"; case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; case ImGuiCol_PlotHistogram: return "PlotHistogram"; @@ -9056,6 +9069,29 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); ImGui::TreePop(); } + + static void NodeTabBar(ImGuiTabBar* tab_bar) + { + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernable strings. + char buf[256]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + p += ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", + tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); + if (ImGui::TreeNode(tab_bar, "%s", buf)) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + ImGui::PushID(tab); + if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); + if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine(); + ImGui::Text("%02d%c Tab 0x%08X", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID); + ImGui::PopID(); + } + ImGui::TreePop(); + } + } }; // Access private state, we are going to display the draw lists from last frame @@ -9076,6 +9112,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImGui::TreePop(); } + if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size)) + { + for (int n = 0; n < g.TabBars.Data.Size; n++) + Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); + ImGui::TreePop(); + } if (ImGui::TreeNode("Internal state")) { const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); diff --git a/imgui.h b/imgui.h index 0d8f1964..2fb09b50 100644 --- a/imgui.h +++ b/imgui.h @@ -135,6 +135,8 @@ typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: f typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText*() typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() +typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode*(),CollapsingHeader() typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin*() typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data); @@ -528,6 +530,14 @@ namespace ImGui IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column IMGUI_API int GetColumnsCount(); + // Tab Bars, Tabs + // [BETA API] API may evolve! + IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar + IMGUI_API void EndTabBar(); + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected. + IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! + IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. + // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file @@ -760,6 +770,31 @@ enum ImGuiComboFlags_ ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest }; +// Flags for ImGui::BeginTabBar() +enum ImGuiTabBarFlags_ +{ + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 5, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 6, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}; + +// Flags for ImGui::BeginTabItem() +enum ImGuiTabItemFlags_ +{ + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker. + ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programatically make the tab selected when calling BeginTabItem() + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() +}; + // Flags for ImGui::IsWindowFocused() enum ImGuiFocusedFlags_ { @@ -956,6 +991,11 @@ enum ImGuiCol_ ImGuiCol_ResizeGrip, ImGuiCol_ResizeGripHovered, ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, ImGuiCol_PlotLines, ImGuiCol_PlotLinesHovered, ImGuiCol_PlotHistogram, @@ -1003,6 +1043,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding ImGuiStyleVar_GrabMinSize, // float GrabMinSize ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_COUNT @@ -1114,6 +1155,8 @@ struct ImGuiStyle float ScrollbarRounding; // Radius of grab corners for scrollbar. float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + float TabBorderSize; // Thickness of border around tabs. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8b90df16..8d9b1193 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -40,6 +40,7 @@ Index of this file: // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() */ @@ -102,6 +103,7 @@ Index of this file: #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Forward Declarations +static void ShowExampleAppDocuments(bool* p_open); static void ShowExampleAppMainMenuBar(); static void ShowExampleAppConsole(bool* p_open); static void ShowExampleAppLog(bool* p_open); @@ -168,6 +170,7 @@ static void ShowDemoWindowMisc(); void ImGui::ShowDemoWindow(bool* p_open) { // Examples Apps (accessible from the "Examples" menu) + static bool show_app_documents = false; static bool show_app_main_menu_bar = false; static bool show_app_console = false; static bool show_app_log = false; @@ -180,6 +183,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool show_app_window_titles = false; static bool show_app_custom_rendering = false; + if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); if (show_app_console) ShowExampleAppConsole(&show_app_console); if (show_app_log) ShowExampleAppLog(&show_app_log); @@ -263,6 +267,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); 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); ImGui::EndMenu(); } if (ImGui::BeginMenu("Help")) @@ -1698,6 +1703,76 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } + if (ImGui::TreeNode("Tabs")) + { + if (ImGui::TreeNode("Basic")) + { + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + if (ImGui::BeginTabItem("Avocado")) + { + ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Broccoli")) + { + ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Cucumber")) + { + ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Advanced & Close Button")) + { + // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + // Tab Bar + const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; + static bool opened[4] = { true, true, true, true }; // Persistent user state + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + { + if (n > 0) { ImGui::SameLine(); } + ImGui::Checkbox(names[n], &opened[n]); + } + + // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed. + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n])) + { + ImGui::Text("This is the %s tab!", names[n]); + if (n & 1) + ImGui::Text("I am an odd tab."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Groups")) { ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)"); @@ -2679,12 +2754,14 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::Text("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); ImGui::Text("Alignment"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); @@ -3758,6 +3835,271 @@ static void ShowExampleAppCustomRendering(bool* p_open) if (adding_preview) points.pop_back(); } +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +//----------------------------------------------------------------------------- + +// Simplified structure to mimic a Document model +struct MyDocument +{ + const char* Name; // Document title + bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo) + bool OpenPrev; // Copy of Open from last update. + bool Dirty; // Set when the document has been modified + bool WantClose; // Set when the document + ImVec4 Color; // An arbitrary variable associated to the document + + MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) + { + Name = name; + Open = OpenPrev = open; + Dirty = false; + WantClose = false; + Color = color; + } + void DoOpen() { Open = true; } + void DoQueueClose() { WantClose = true; } + void DoForceClose() { Open = false; Dirty = false; } + void DoSave() { Dirty = false; } + + // Display dummy contents for the Document + static void DisplayContents(MyDocument* doc) + { + ImGui::PushID(doc); + ImGui::Text("Document \"%s\"", doc->Name); + ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); + ImGui::PopStyleColor(); + if (ImGui::Button("Modify", ImVec2(100, 0))) + doc->Dirty = true; + ImGui::SameLine(); + if (ImGui::Button("Save", ImVec2(100, 0))) + doc->DoSave(); + ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui::PopID(); + } + + // Display context menu for the Document + static void DisplayContextMenu(MyDocument* doc) + { + if (!ImGui::BeginPopupContextItem()) + return; + + char buf[256]; + sprintf(buf, "Save %s", doc->Name); + if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) + doc->DoSave(); + if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) + doc->DoQueueClose(); + ImGui::EndPopup(); + } +}; + +struct ExampleAppDocuments +{ + ImVector Documents; + + ExampleAppDocuments() + { + Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); + Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); + Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("A Rather Long Title", false)); + Documents.push_back(MyDocument("Some Document", false)); + } +}; + +// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed +// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. +// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar +// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame. +// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. +static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) +{ + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open && doc->OpenPrev) + ImGui::SetTabItemClosed(doc->Name); + doc->OpenPrev = doc->Open; + } +} + +void ShowExampleAppDocuments(bool* p_open) +{ + static ExampleAppDocuments app; + + ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar); + + // Options + static bool opt_reorderable = true; + static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; + + // Menu + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + int open_count = 0; + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + open_count += app.Documents[doc_n].Open ? 1 : 0; + + if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) + { + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + if (ImGui::MenuItem(doc->Name)) + doc->DoOpen(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + app.Documents[doc_n].DoQueueClose(); + if (ImGui::MenuItem("Exit", "Alt+F4")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // [Debug] List documents with one checkbox for each + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc_n > 0) + ImGui::SameLine(); + ImGui::PushID(doc); + if (ImGui::Checkbox(doc->Name, &doc->Open)) + if (!doc->Open) + doc->DoForceClose(); + ImGui::PopID(); + } + + ImGui::Separator(); + + // Submit Tab Bar and Tabs + { + ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); + if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) + { + if (opt_reorderable) + NotifyOfDocumentsClosedElsewhere(app); + + // [DEBUG] Stress tests + //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. + + // Submit Tabs + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + continue; + + ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); + bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); + + // Cancel attempt to close when unsaved add to save queue so we can display a popup. + if (!doc->Open && doc->Dirty) + { + doc->Open = true; + doc->DoQueueClose(); + } + + MyDocument::DisplayContextMenu(doc); + if (visible) + { + MyDocument::DisplayContents(doc); + ImGui::EndTabItem(); + } + } + + ImGui::EndTabBar(); + } + } + + // Update closing queue + static ImVector close_queue; + if (close_queue.empty()) + { + // Close queue is locked once we started a popup + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc->WantClose) + { + doc->WantClose = false; + close_queue.push_back(doc); + } + } + } + + // Display closing confirmation UI + if (!close_queue.empty()) + { + int close_queue_unsaved_documents = 0; + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + close_queue_unsaved_documents++; + + if (close_queue_unsaved_documents == 0) + { + // Close documents when all are unsaved + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + } + else + { + if (!ImGui::IsPopupOpen("Save?")) + ImGui::OpenPopup("Save?"); + if (ImGui::BeginPopupModal("Save?")) + { + ImGui::Text("Save change to the following items?"); + ImGui::PushItemWidth(-1.0f); + ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6); + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + ImGui::Text("%s", close_queue[n]->Name); + ImGui::ListBoxFooter(); + + if (ImGui::Button("Yes", ImVec2(80, 0))) + { + for (int n = 0; n < close_queue.Size; n++) + { + if (close_queue[n]->Dirty) + close_queue[n]->DoSave(); + close_queue[n]->DoForceClose(); + } + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No", ImVec2(80, 0))) + { + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(80, 0))) + { + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + } + ImGui::End(); } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5346ad51..ea89a5f6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -205,6 +205,11 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); @@ -255,6 +260,11 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); @@ -306,6 +316,11 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); @@ -2821,6 +2836,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col // - RenderMouseCursor() // - RenderArrowPointingAt() // - RenderRectFilledRangeH() +// - RenderPixelEllipsis() //----------------------------------------------------------------------------- void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor) @@ -2929,6 +2945,15 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im draw_list->PathFillConvex(col); } +// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, +// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match +// the boldness or positioning of what the font uses... +void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col) +{ + pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); + for (int dot_n = 0; dot_n < count; dot_n++) + draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); +} //----------------------------------------------------------------------------- // [SECTION] Decompression code diff --git a/imgui_internal.h b/imgui_internal.h index c1d0016d..033888ef 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -49,6 +49,8 @@ struct ImGuiNextWindowData; // Storage for SetNexWindow** functions struct ImGuiPopupRef; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it +struct ImGuiTabBar; // Storage for a tab bar +struct ImGuiTabItem; // Storage for a tab item (within a tab bar) struct ImGuiWindow; // Storage for one window struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame) struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session) @@ -679,6 +681,12 @@ struct ImGuiNextWindowData } }; +struct ImGuiTabBarSortItem +{ + int Index; + float Width; +}; + //----------------------------------------------------------------------------- // Main imgui context //----------------------------------------------------------------------------- @@ -804,6 +812,11 @@ struct ImGuiContext ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads + // Tab bars + ImPool TabBars; + ImVector CurrentTabBar; + ImVector TabSortByWidthBuffer; + // Widget state ImGuiInputTextState InputTextState; ImFont InputTextPasswordFont; @@ -1154,6 +1167,59 @@ struct ImGuiItemHoveredDataBackup void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } }; +//----------------------------------------------------------------------------- +// Tab Bar, Tab Item +//----------------------------------------------------------------------------- + +enum ImGuiTabBarFlagsPrivate_ +{ + ImGuiTabBarFlags_DockNode = 1 << 20, // [Docking: Unused in Master Branch] Part of a dock node + ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // [Docking: Unused in Master Branch] Part of an explicit dockspace node node + ImGuiTabBarFlags_IsFocused = 1 << 22, + ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs +}; + +// Storage for one active tab item (sizeof() 26~32 bytes) +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + float Offset; // Position relative to beginning of tab + float Width; // Width currently displayed + float WidthContents; // Width of actual contents, stored during BeginTabItem() call + + ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; } +}; + +// Storage for a tab bar (sizeof() 92~96 bytes) +struct ImGuiTabBar +{ + ImVector Tabs; + ImGuiID ID; // Zero for tab-bars used by docking + ImGuiID SelectedTabId; // Selected tab + ImGuiID NextSelectedTabId; + ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float ContentsHeight; + float OffsetMax; // Distance from BarRect.Min.x, locked during layout + float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set. + float ScrollingAnim; + float ScrollingTarget; + ImGuiTabBarFlags Flags; + ImGuiID ReorderRequestTabId; + int ReorderRequestDir; + bool WantLayout; + bool VisibleTabWasSubmitted; + short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + + ImGuiTabBar(); + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_pointer(tab); } +}; + //----------------------------------------------------------------------------- // Internal API // No guarantee of forward compatibility here. @@ -1270,12 +1336,24 @@ namespace ImGui IMGUI_API void EndColumns(); // close columns IMGUI_API void PushColumnClipRect(int column_index = -1); + // Tab Bars + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); + IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); + IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); + IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id); + // Render helpers // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); @@ -1290,6 +1368,7 @@ namespace ImGui IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow); IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); + IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col); // Widgets IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 126fcf31..8f524ba7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -22,6 +22,8 @@ Index of this file: // [SECTION] Widgets: PlotLines, PlotHistogram // [SECTION] Widgets: Value helpers // [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc. +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. */ @@ -5748,3 +5750,791 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, } return false; } + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +//------------------------------------------------------------------------- +// [BETA API] API may evolve! This code has been extracted out of the Docking branch, +// and some of the construct which are not used in Master may be left here to facilitate merging. +//------------------------------------------------------------------------- +// - BeginTabBar() +// - BeginTabBarEx() [Internal] +// - EndTabBar() +// - TabBarLayout() [Internal] +// - TabBarCalcTabID() [Internal] +// - TabBarCalcMaxTabWidth() [Internal] +// - TabBarFindTabById() [Internal] +// - TabBarRemoveTab() [Internal] +// - TabBarCloseTab() [Internal] +// - TabBarScrollClamp()v +// - TabBarScrollToTab() [Internal] +// - TabBarQueueChangeTabOrder() [Internal] +// - TabBarScrollingButtons() [Internal] +//------------------------------------------------------------------------- + +namespace ImGui +{ + static void TabBarLayout(ImGuiTabBar* tab_bar); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); + static float TabBarCalcMaxTabWidth(); + static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); +} + +ImGuiTabBar::ImGuiTabBar() +{ + ID = 0; + SelectedTabId = NextSelectedTabId = VisibleTabId = 0; + CurrFrameVisible = PrevFrameVisible = -1; + OffsetMax = OffsetNextTab = 0.0f; + ScrollingAnim = ScrollingTarget = 0.0f; + Flags = ImGuiTabBarFlags_None; + ReorderRequestTabId = 0; + ReorderRequestDir = 0; + WantLayout = VisibleTabWasSubmitted = false; + LastTabItemIdx = -1; +} + +static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + return (int)(a->Offset - b->Offset); +} + +static int IMGUI_CDECL TabBarSortItemComparer(const void* lhs, const void* rhs) +{ + const ImGuiTabBarSortItem* a = (const ImGuiTabBarSortItem*)lhs; + const ImGuiTabBarSortItem* b = (const ImGuiTabBarSortItem*)rhs; + if (int d = (int)(b->Width - a->Width)) + return d; + return (b->Index - a->Index); +} + +bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(str_id); + ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerClipRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + tab_bar->ID = id; + return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused); +} + +bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + if ((flags & ImGuiTabBarFlags_DockNode) == 0) + window->IDStack.push_back(tab_bar->ID); + + g.CurrentTabBar.push_back(tab_bar); + if (tab_bar->CurrFrameVisible == g.FrameCount) + { + //printf("[%05d] BeginTabBarEx already called this frame\n", g.FrameCount); + IM_ASSERT(0); + return true; + } + + // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. + // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. + if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); + + // Flags + if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + + tab_bar->Flags = flags; + tab_bar->BarRect = tab_bar_bb; + tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() + tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; + tab_bar->CurrFrameVisible = g.FrameCount; + + // Layout + ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); + window->DC.CursorPos.x = tab_bar->BarRect.Min.x; + + // Draw separator + const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab); + const float y = tab_bar->BarRect.Max.y - 1.0f; + { + const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); + const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + } + return true; +} + +void ImGui::EndTabBar() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + IM_ASSERT(!g.CurrentTabBar.empty()); // Mismatched BeginTabBar/EndTabBar + ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) + tab_bar->ContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f); + else + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->ContentsHeight; + + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + PopID(); + g.CurrentTabBar.pop_back(); +} + +// This is called only once a frame before by the first call to ItemTab() +// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. +static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + tab_bar->WantLayout = false; + + // Garbage collect + int tab_dst_n = 0; + for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; + if (tab->LastFrameVisible < tab_bar->PrevFrameVisible) + { + if (tab->ID == tab_bar->SelectedTabId) + tab_bar->SelectedTabId = 0; + continue; + } + if (tab_dst_n != tab_src_n) + tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n]; + tab_dst_n++; + } + if (tab_bar->Tabs.Size != tab_dst_n) + tab_bar->Tabs.resize(tab_dst_n); + + // Setup next selected tab + ImGuiID scroll_track_selected_tab_id = 0; + if (tab_bar->NextSelectedTabId) + { + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; + tab_bar->NextSelectedTabId = 0; + scroll_track_selected_tab_id = tab_bar->SelectedTabId; + } + + // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). + if (tab_bar->ReorderRequestTabId != 0) + { + if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId)) + { + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; + if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size) + { + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + ImGuiTabItem item_tmp = *tab1; + *tab1 = *tab2; + *tab2 = item_tmp; + if (tab2->ID == tab_bar->SelectedTabId) + scroll_track_selected_tab_id = tab2->ID; + tab1 = tab2 = NULL; + } + if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) + MarkIniSettingsDirty(); + } + tab_bar->ReorderRequestTabId = 0; + } + + ImVector& width_sort_buffer = g.TabSortByWidthBuffer; + width_sort_buffer.resize(tab_bar->Tabs.Size); + + // Compute ideal widths + float width_total_contents = 0.0f; + ImGuiTabItem* most_recently_selected_tab = NULL; + bool found_selected_tab_id = false; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); + + if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) + most_recently_selected_tab = tab; + if (tab->ID == tab_bar->SelectedTabId) + found_selected_tab_id = true; + + // Refresh tab width immediately if we can (for manual tab bar, WidthContent will lag by one frame which is mostly noticeable when changing style.FramePadding.x) + // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, + // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. + width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; + + // Store data so we can build an array sorted by width if we need to shrink tabs down + width_sort_buffer[tab_n].Index = tab_n; + width_sort_buffer[tab_n].Width = tab->WidthContents; + } + + // Compute width + const float width_avail = tab_bar->BarRect.GetWidth(); + float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f; + if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) + { + // If we don't have enough room, resize down the largest tabs first + if (tab_bar->Tabs.Size > 1) + ImQsort(width_sort_buffer.Data, (size_t)width_sort_buffer.Size, sizeof(ImGuiTabBarSortItem), TabBarSortItemComparer); + int tab_count_same_width = 1; + while (width_excess > 0.0f && tab_count_same_width < tab_bar->Tabs.Size) + { + while (tab_count_same_width < tab_bar->Tabs.Size && width_sort_buffer[0].Width == width_sort_buffer[tab_count_same_width].Width) + tab_count_same_width++; + float width_to_remove_per_tab_max = (tab_count_same_width < tab_bar->Tabs.Size) ? (width_sort_buffer[0].Width - width_sort_buffer[tab_count_same_width].Width) : (width_sort_buffer[0].Width - 1.0f); + float width_to_remove_per_tab = ImMin(width_excess / tab_count_same_width, width_to_remove_per_tab_max); + for (int tab_n = 0; tab_n < tab_count_same_width; tab_n++) + width_sort_buffer[tab_n].Width -= width_to_remove_per_tab; + width_excess -= width_to_remove_per_tab * tab_count_same_width; + } + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + tab_bar->Tabs[width_sort_buffer[tab_n].Index].Width = (float)(int)width_sort_buffer[tab_n].Width; + } + else + { + const float tab_max_width = TabBarCalcMaxTabWidth(); + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + tab->Width = ImMin(tab->WidthContents, tab_max_width); + } + } + + // Layout all active tabs + float offset_x = 0.0f; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + tab->Offset = offset_x; + if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_track_selected_tab_id = tab->ID; + offset_x += tab->Width + g.Style.ItemInnerSpacing.x; + } + tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); + tab_bar->OffsetNextTab = 0.0f; + + // Horizontal scrolling buttons + const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); + if (scrolling_buttons) + if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x! + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + // If we have lost the selected tab, select the next most recently active one + if (found_selected_tab_id == false) + tab_bar->SelectedTabId = 0; + if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) + scroll_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + + // Lock in visible tab + tab_bar->VisibleTabId = tab_bar->SelectedTabId; + tab_bar->VisibleTabWasSubmitted = false; + + // Update scrolling + if (scroll_track_selected_tab_id) + if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id)) + TabBarScrollToTab(tab_bar, scroll_track_selected_tab); + tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); + const float scrolling_speed = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) ? FLT_MAX : (g.IO.DeltaTime * g.FontSize * 70.0f); + if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) + tab_bar->ScrollingAnim = ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, scrolling_speed); +} + +// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) +{ + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + ImGuiID id = ImHash(label, 0); + KeepAliveID(id); + return id; + } + else + { + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(label); + } +} + +static float ImGui::TabBarCalcMaxTabWidth() +{ + ImGuiContext& g = *GImGui; + return g.FontSize * 20.0f; +} + +ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (tab_id != 0) + for (int n = 0; n < tab_bar->Tabs.Size; n++) + if (tab_bar->Tabs[n].ID == tab_id) + return &tab_bar->Tabs[n]; + return NULL; +} + +// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab_bar->Tabs.erase(tab); + if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; } +} + +// Called on manual closure attempt +void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if ((tab_bar->VisibleTabId == tab->ID) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // This will remove a frame of lag for selecting another tab on closure. + // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } + else if ((tab_bar->VisibleTabId != tab->ID) && (tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // Actually select before expecting closure + tab_bar->NextSelectedTabId = tab->ID; + } +} + +static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +{ + scrolling = ImMin(scrolling, tab_bar->OffsetMax - tab_bar->BarRect.GetWidth()); + return ImMax(scrolling, 0.0f); +} + +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + ImGuiContext& g = *GImGui; + float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + int order = tab_bar->GetTabOrder(tab); + float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f); + float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f); + if (tab_bar->ScrollingTarget > tab_x1) + tab_bar->ScrollingTarget = tab_x1; + if (tab_bar->ScrollingTarget + tab_bar->BarRect.GetWidth() < tab_x2) + tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth(); +} + +void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir) +{ + IM_ASSERT(dir == -1 || dir == +1); + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + tab_bar->ReorderRequestTabId = tab->ID; + tab_bar->ReorderRequestDir = dir; +} + +static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); + const float scrolling_buttons_width = arrow_button_size.x * 2.0f; + + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); + + const ImRect avail_bar_rect = tab_bar->BarRect; + bool want_clip_rect = !avail_bar_rect.Contains(ImRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(scrolling_buttons_width, 0.0f))); + if (want_clip_rect) + PushClipRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max + ImVec2(g.Style.ItemInnerSpacing.x, 0.0f), true); + + ImGuiTabItem* tab_to_select = NULL; + + int select_dir = 0; + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + const float backup_repeat_delay = g.IO.KeyRepeatDelay; + const float backup_repeat_rate = g.IO.KeyRepeatRate; + g.IO.KeyRepeatDelay = 0.250f; + g.IO.KeyRepeatRate = 0.200f; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = -1; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width + arrow_button_size.x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = +1; + PopStyleColor(2); + g.IO.KeyRepeatRate = backup_repeat_rate; + g.IO.KeyRepeatDelay = backup_repeat_delay; + + if (want_clip_rect) + PopClipRect(); + + if (select_dir != 0) + if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + { + int selected_order = tab_bar->GetTabOrder(tab_item); + int target_order = selected_order + select_dir; + tab_to_select = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; // If we are at the end of the list, still scroll to make our tab visible + } + window->DC.CursorPos = backup_cursor_pos; + tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f; + + return tab_to_select; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +//------------------------------------------------------------------------- +// [BETA API] API may evolve! This code has been extracted out of the Docking branch, +// and some of the construct which are not used in Master may be left here to facilitate merging. +//------------------------------------------------------------------------- +// - BeginTabItem() +// - EndTabItem() +// - TabItemEx() [Internal] +// - SetTabItemClosed() +// - TabItemCalcSize() [Internal] +// - TabItemRenderBackground() [Internal] +// - TabItemLabelAndCloseButton() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return false; + + IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!"); + ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); + bool ret = TabItemEx(tab_bar, label, p_open, flags); + if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) + PushID(tab_bar->Tabs[tab_bar->LastTabItemIdx].ID); + return ret; +} + +void ImGui::EndTabItem() +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + + IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!"); + ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) + PopID(); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + // Layout whole tab bar if not already done + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = TabBarCalcTabID(tab_bar, label); + + // If the user called us with *p_open == false, we early out and don't render. We make a dummy call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + if (p_open && !*p_open) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return false; + } + + // Calculate tab contents size + ImVec2 size = TabItemCalcSize(label, p_open != NULL); + + // Acquire tab data + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); + bool tab_is_new = false; + if (tab == NULL) + { + tab_bar->Tabs.push_back(ImGuiTabItem()); + tab = &tab_bar->Tabs.back(); + tab->ID = id; + tab->Width = size.x; + tab_is_new = true; + } + tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_pointer(tab); + tab->WidthContents = size.x; + + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; + const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); + tab->LastFrameVisible = g.FrameCount; + tab->Flags = flags; + + // If we are not reorderable, always reset offset based on submission order. + // (We already handled layout and sizing using the previous known order, but sizing is not affected by order!) + if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + tab->Offset = tab_bar->OffsetNextTab; + tab_bar->OffsetNextTab += tab->Width + g.Style.ItemInnerSpacing.x; + } + + // Update selected tab + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + tab_bar->NextSelectedTabId = id; // New tabs gets activated + + // Lock visibility + bool tab_contents_visible = (tab_bar->VisibleTabId == id); + if (tab_contents_visible) + tab_bar->VisibleTabWasSubmitted = true; + + // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches + if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing) + if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) + tab_contents_visible = true; + + if (tab_appearing && !(tab_bar_appearing && !tab_is_new)) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return tab_contents_visible; + } + + if (tab_bar->SelectedTabId == id) + tab->LastFrameSelected = g.FrameCount; + + // Backup current layout position + const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; + + // Layout + size.x = tab->Width; + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2((float)(int)tab->Offset - tab_bar->ScrollingAnim, 0.0f); + ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + size); + + // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) + bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x >= tab_bar->BarRect.Max.x); + if (want_clip_rect) + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true); + + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(bb, id)) + { + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + return tab_contents_visible; + } + + // Click to Select a tab + ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap); + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + hovered |= (g.HoveredId == id); + if (pressed || ((flags & ImGuiTabItemFlags_SetSelected) && !tab_contents_visible)) // SetSelected can only be passed on explicit tab bar + tab_bar->NextSelectedTabId = id; + + // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) + if (!held) + SetItemAllowOverlap(); + + // Drag and drop: re-order tabs + if (held && !tab_appearing && IsMouseDragging(0)) + { + if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) + { + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueChangeTabOrder(tab_bar, tab, -1); + } + else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) + { + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueChangeTabOrder(tab_bar, tab, +1); + } + } + } + +#if 0 + if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->WidthContents) + { + // Enlarge tab display when hovering + bb.Max.x = bb.Min.x + (float)(int)ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f)); + display_draw_list = GetOverlayDrawList(window); + TabItemRenderBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); + } +#endif + + // Render tab shape + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + RenderNavHighlight(bb, id); + + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) + tab_bar->NextSelectedTabId = id; + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? window->GetID((void*)(intptr_t)(id + 1)) : 0; + bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id); + if (just_closed) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Restore main window position so user can draw there + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + + // Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer) + if (g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > 0.50f) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + return tab_contents_visible; +} + +// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. +// To use it to need to call the function SetTabItemClosed() after BeginTabBar() and before any call to BeginTabItem() +void ImGui::SetTabItemClosed(const char* label) +{ + ImGuiContext& g = *GImGui; + bool is_within_manual_tab_bar = (g.CurrentTabBar.Size > 0) && !(g.CurrentTabBar.back()->Flags & ImGuiTabBarFlags_DockNode); + if (is_within_manual_tab_bar) + { + ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); + IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem() + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); + TabBarRemoveTab(tab_bar, tab_id); + } +} + +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); + if (has_close_button) + size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. + else + size.x += g.Style.FramePadding.x + 1.0f; + return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); +} + +void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +{ + // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. + (void)flags; + ImGuiContext& g = *GImGui; + const float width = bb.GetWidth(); + IM_ASSERT(width > 0.0f); + const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f)); + float y1 = bb.Min.y + 1.0f; + float y2 = bb.Max.y - 1.0f; + draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->AddConvexPolyFilled(draw_list->_Path.Data, draw_list->_Path.Size, col); + if (g.Style.TabBorderSize > 0.0f) + draw_list->AddPolyline(draw_list->_Path.Data, draw_list->_Path.Size, GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize); + draw_list->PathClear(); +} + +// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic +bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImVec2 label_size = CalcTextSize(label, NULL, true); + if (bb.GetWidth() <= 1.0f) + return false; + + // Render text label (with clipping + alpha gradient) + unsaved marker + const char* TAB_UNSAVED_MARKER = "*"; + ImRect text_pixel_clip_bb(bb.Min.x + style.FramePadding.x, bb.Min.y + style.FramePadding.y, bb.Max.x - style.FramePadding.x, bb.Max.y); + if (flags & ImGuiTabItemFlags_UnsavedDocument) + { + text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; + ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + style.FramePadding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + style.FramePadding.y + (float)(int)(-g.FontSize * 0.25f)); + RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - style.FramePadding, TAB_UNSAVED_MARKER, NULL, NULL); + } + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + // Close Button + // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() + // 'hovered' will be true when hovering the Tab but NOT when hovering the close button + // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button + // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false + bool close_button_pressed = false; + bool close_button_visible = false; + if (close_button_id != 0) + if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == close_button_id) + close_button_visible = true; + if (close_button_visible) + { + ImGuiItemHoveredDataBackup last_item_backup; + const float close_button_sz = g.FontSize * 0.5f; + if (CloseButton(close_button_id, ImVec2(bb.Max.x - style.FramePadding.x - close_button_sz, bb.Min.y + style.FramePadding.y + close_button_sz), close_button_sz)) + close_button_pressed = true; + last_item_backup.Restore(); + + // Close with middle mouse button + if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + close_button_pressed = true; + + text_pixel_clip_bb.Max.x -= close_button_sz * 2.0f; + } + + // Label with ellipsis + // FIXME: This should be extracted into a helper but the use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment + const char* label_display_end = FindRenderedTextEnd(label); + if (label_size.x > text_ellipsis_clip_bb.GetWidth()) + { + const int ellipsis_dot_count = 3; + const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f; + const char* label_end = NULL; + float label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, text_ellipsis_clip_bb.GetWidth() - ellipsis_width + 1.0f, 0.0f, label, label_display_end, &label_end).x; + if (label_end == label && label_end < label_display_end) // Always display at least 1 character if there's no room for character + ellipsis + { + label_end = label + ImTextCountUtf8BytesFromChar(label, label_display_end); + label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label, label_end).x; + } + while (label_end > label && ImCharIsBlankA(label_end[-1])) // Trim trailing space + { + label_end--; + label_size_clipped_x -= g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label_end, label_end + 1).x; // Ascii blanks are always 1 byte + } + RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_end, &label_size, ImVec2(0.0f, 0.0f)); + + const float ellipsis_x = text_pixel_clip_bb.Min.x + label_size_clipped_x + 1.0f; + if (!close_button_visible && ellipsis_x + ellipsis_width <= bb.Max.x) + RenderPixelEllipsis(draw_list, g.Font, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text)); + } + else + { + RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_display_end, &label_size, ImVec2(0.0f, 0.0f)); + } + + return close_button_pressed; +} From 95dcc534ed9faae523492b07db439440a4043800 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 13:25:16 +0100 Subject: [PATCH 015/195] Demo: Fix collateral damage of 54a60aa --- imgui_demo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8d9b1193..4159a01d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3835,6 +3835,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) if (adding_preview) points.pop_back(); } + ImGui::End(); } //----------------------------------------------------------------------------- From 2886e0b6f5ff45e4f60c0312d936db837d403843 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 13:25:16 +0100 Subject: [PATCH 016/195] Demo: Fix collateral damage of 54a60aa --- imgui_demo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d86606dd..d5708bcc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3863,6 +3863,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) if (adding_preview) points.pop_back(); } + ImGui::End(); } //----------------------------------------------------------------------------- From 5a6b8e00dbd2271f433dfb5e1ec9b25ee9bf0781 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 15:22:10 +0100 Subject: [PATCH 017/195] BeginTabBar: Fix to push the expected ID into the ID stack (instead of a hash's hash). (#261) --- imgui_widgets.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8f524ba7..d08583a1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6218,7 +6218,10 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); bool ret = TabItemEx(tab_bar, label, p_open, flags); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) - PushID(tab_bar->Tabs[tab_bar->LastTabItemIdx].ID); + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + g.CurrentWindow->IDStack.push_back(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + } return ret; } @@ -6232,7 +6235,7 @@ void ImGui::EndTabItem() ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) - PopID(); + g.CurrentWindow->IDStack.pop_back(); } bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) From ccce47c6a2b5799d140d4dc9f6fd01b2cdcf80e4 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 16:59:17 +0100 Subject: [PATCH 018/195] Demo: Using Tabs in Style Editor and Simple Layout example. + Adding missing early out in About and Documents examples. --- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- imgui_demo.cpp | 341 ++++++++++++++++++++++++--------------------- 3 files changed, 188 insertions(+), 156 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3ecb60ec..601a7abf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other Changes: This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. +- Demo: "Simple Layout" and "Style Editor" are now using tabs. - Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file to ease integration. diff --git a/imgui.h b/imgui.h index 2fb09b50..d43752f8 100644 --- a/imgui.h +++ b/imgui.h @@ -533,7 +533,7 @@ namespace ImGui // Tab Bars, Tabs // [BETA API] API may evolve! IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar - IMGUI_API void EndTabBar(); + IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected. IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4159a01d..f173221f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2534,7 +2534,11 @@ static void ShowDemoWindowMisc() void ImGui::ShowAboutWindow(bool* p_open) { - ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize); + if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); ImGui::Separator(); ImGui::Text("By Omar Cornut and all dear imgui contributors."); @@ -2726,188 +2730,198 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SameLine(); ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere."); - if (ImGui::TreeNode("Rendering")) - { - ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); - ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); - ImGui::PushItemWidth(100); - ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f); - if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; - ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - ImGui::PopItemWidth(); - ImGui::TreePop(); - } + ImGui::Separator(); - if (ImGui::TreeNode("Settings")) + if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) { - ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); - ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); - ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); - ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); - ImGui::Text("BorderSize"); - ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::Text("Rounding"); - ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f"); - ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f"); - ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); - ImGui::Text("Alignment"); - ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); - ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); - ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); - ImGui::TreePop(); - } + if (ImGui::BeginTabItem("Sizes")) + { + ImGui::Text("Main"); + ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); + ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); + ImGui::Text("Borders"); + ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::Text("Rounding"); + ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f"); + ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f"); + ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::Text("Alignment"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); + ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + ImGui::EndTabItem(); + } - if (ImGui::TreeNode("Colors")) - { - static int output_dest = 0; - static bool output_only_modified = true; - if (ImGui::Button("Export Unsaved")) + if (ImGui::BeginTabItem("Colors")) { - if (output_dest == 0) - ImGui::LogToClipboard(); - else - ImGui::LogToTTY(); - ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); - for (int i = 0; i < ImGuiCol_COUNT; i++) + static int output_dest = 0; + static bool output_only_modified = true; + if (ImGui::Button("Export Unsaved")) { - const ImVec4& col = style.Colors[i]; - const char* name = ImGui::GetStyleColorName(i); - if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) - ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23-(int)strlen(name), "", col.x, col.y, col.z, col.w); + if (output_dest == 0) + ImGui::LogToClipboard(); + else + ImGui::LogToTTY(); + ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const ImVec4& col = style.Colors[i]; + const char* name = ImGui::GetStyleColorName(i); + if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) + ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); + } + ImGui::LogFinish(); } - ImGui::LogFinish(); - } - ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); - ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); + ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); + ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); - ImGui::Text("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu."); + static ImGuiTextFilter filter; + filter.Draw("Filter colors", ImGui::GetFontSize() * 16); - static ImGuiTextFilter filter; - filter.Draw("Filter colors", 200); - - static ImGuiColorEditFlags alpha_flags = 0; - ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine(); - ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine(); - ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); + static ImGuiColorEditFlags alpha_flags = 0; + ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine(); + ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine(); + ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::SameLine(); + ShowHelpMarker("In the color list:\nLeft-click on colored square to open color picker,\nRight-click to open edit options menu."); - ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); - ImGui::PushItemWidth(-160); - for (int i = 0; i < ImGuiCol_COUNT; i++) - { - const char* name = ImGui::GetStyleColorName(i); - if (!filter.PassFilter(name)) - continue; - ImGui::PushID(i); - ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); - if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); + ImGui::PushItemWidth(-160); + for (int i = 0; i < ImGuiCol_COUNT; i++) { - // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. - // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient! - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; + const char* name = ImGui::GetStyleColorName(i); + if (!filter.PassFilter(name)) + continue; + ImGui::PushID(i); + ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + { + // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. + // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient! + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; + } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); + ImGui::TextUnformatted(name); + ImGui::PopID(); } - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); - ImGui::TextUnformatted(name); - ImGui::PopID(); - } - ImGui::PopItemWidth(); - ImGui::EndChild(); - - ImGui::TreePop(); - } + ImGui::PopItemWidth(); + ImGui::EndChild(); - bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size); - if (fonts_opened) - { - ImFontAtlas* atlas = ImGui::GetIO().Fonts; - if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) - { - ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); - ImGui::TreePop(); + ImGui::EndTabItem(); } - ImGui::PushItemWidth(100); - for (int i = 0; i < atlas->Fonts.Size; i++) + + if (ImGui::BeginTabItem("Fonts")) { - ImFont* font = atlas->Fonts[i]; - ImGui::PushID(font); - bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; - if (font_details_opened) + ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); + ImGui::PushItemWidth(120); + for (int i = 0; i < atlas->Fonts.Size; i++) { - ImGui::PushFont(font); - ImGui::Text("The quick brown fox jumps over the lazy dog"); - ImGui::PopFont(); - ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font - ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); - ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); - ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); - ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); - ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface)); - for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) - if (ImFontConfig* cfg = &font->ConfigData[config_i]) - ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); - if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + ImFont* font = atlas->Fonts[i]; + ImGui::PushID(font); + bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; + if (font_details_opened) { - // Display all glyphs of the fonts in separate pages of 256 characters - for (int base = 0; base < 0x10000; base += 256) + ImGui::PushFont(font); + ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::PopFont(); + ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font + ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); + ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); + ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); + ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface)); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + if (ImFontConfig* cfg = &font->ConfigData[config_i]) + ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); + if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { - int count = 0; - for (int n = 0; n < 256; n++) - count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; - if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base+255, count, count > 1 ? "glyphs" : "glyph")) + // Display all glyphs of the fonts in separate pages of 256 characters + for (int base = 0; base < 0x10000; base += 256) { - float cell_size = font->FontSize * 1; - float cell_spacing = style.ItemSpacing.y; - ImVec2 base_pos = ImGui::GetCursorScreenPos(); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); + int count = 0; for (int n = 0; n < 256; n++) + count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; + if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) { - ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); - ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base+n)); - draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50)); - if (glyph) - font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. - if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) + float cell_size = font->FontSize * 1; + float cell_spacing = style.ItemSpacing.y; + ImVec2 base_pos = ImGui::GetCursorScreenPos(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 256; n++) { - ImGui::BeginTooltip(); - ImGui::Text("Codepoint: U+%04X", base+n); - ImGui::Separator(); - ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); - ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); - ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); - ImGui::EndTooltip(); + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (glyph) + font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. + if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) + { + ImGui::BeginTooltip(); + ImGui::Text("Codepoint: U+%04X", base + n); + ImGui::Separator(); + ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); + ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); + ImGui::EndTooltip(); + } } + ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + ImGui::TreePop(); } - ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); - ImGui::TreePop(); } + ImGui::TreePop(); } ImGui::TreePop(); } + ImGui::PopID(); + } + if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); ImGui::TreePop(); } - ImGui::PopID(); + + static float window_scale = 1.0f; + if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window + ImGui::SetWindowFontScale(window_scale); + ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); } - static float window_scale = 1.0f; - ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window - ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything - ImGui::PopItemWidth(); - ImGui::SetWindowFontScale(window_scale); - ImGui::TreePop(); + + if (ImGui::BeginTabItem("Rendering")) + { + ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + ImGui::PushItemWidth(100); + ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f); + if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); } ImGui::PopItemWidth(); @@ -3447,7 +3461,20 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us ImGui::Text("MyObject: %d", selected); ImGui::Separator(); - ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Description")) + { + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Details")) + { + ImGui::Text("ID: 0123456789"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } ImGui::EndChild(); if (ImGui::Button("Revert")) {} ImGui::SameLine(); @@ -3935,7 +3962,11 @@ void ShowExampleAppDocuments(bool* p_open) { static ExampleAppDocuments app; - ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar); + if (!ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar)) + { + ImGui::End(); + return; + } // Options static bool opt_reorderable = true; From d9a84de9d9c28751bb8ea0ed24e4f3f1cc0e711f Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 19:08:06 +0100 Subject: [PATCH 019/195] Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. --- docs/CHANGELOG.txt | 5 +++-- imgui.cpp | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 601a7abf..2026df0a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,9 +50,10 @@ Other Changes: (It does not provide the docking/splitting/merging of windows available in the Docking branch) - Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience to avoid using the ### operator. -- Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that +- Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. +- Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. -- Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). +- Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. diff --git a/imgui.cpp b/imgui.cpp index 99feb1b5..3b01d094 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4332,6 +4332,9 @@ static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) static ImVec2 CalcSizeContents(ImGuiWindow* window) { + if (window->Collapsed) + return window->SizeContents; + ImVec2 sz; sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x)); sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y)); From febc3e6aa19e4b1af6c3fa46560e08c4446ca831 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 2 Jul 2018 22:53:59 +0200 Subject: [PATCH 020/195] Internals: Windows hidden with HiddenFramesRegular (but NOT HiddenFramesForResize) preserve their SizeContents, so restoring a auto-resize window after it's been hidden by tabs won't reset its size for a frame. Arguable. Let's see how it goes. (Followup to b48e295bddbf965d7382ec5578ed05d2fe601114) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2026df0a..9b303233 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,7 @@ Other Changes: - Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience to avoid using the ### operator. - Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. +- Window: Contents size is preserved while a window contents is hidden (unless it is hidden for resizing purpose). - Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. - Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). diff --git a/imgui.cpp b/imgui.cpp index 3b01d094..652c4095 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4334,6 +4334,8 @@ static ImVec2 CalcSizeContents(ImGuiWindow* window) { if (window->Collapsed) return window->SizeContents; + if (window->Hidden && window->HiddenFramesForResize == 0 && window->HiddenFramesRegular > 0) + return window->SizeContents; ImVec2 sz; sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x)); From 1b263f6ab0ae6cbf55d83f207802d7994687f826 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 11 Dec 2018 19:37:22 +0100 Subject: [PATCH 021/195] Tabs: Fixed support for drag and drop ImGuiButtonFlags_PressedOnDragDropHold. (#261) incorrectly missing from the merge from Docking branch. --- imgui_widgets.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d08583a1..672fa5ca 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6343,6 +6343,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Click to Select a tab ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap); + if (g.DragDropActive) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); hovered |= (g.HoveredId == id); From e50894c95ebf87b0730be7502e48a1c5648de147 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 13 Dec 2018 19:16:34 +0100 Subject: [PATCH 022/195] Metrics: Fixed crash when viewports are disabled (g.MouseLastHoveredViewport is never set). --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 908e8776..db367eef 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10263,7 +10263,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); - ImGui::Text("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport->ID, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport->ID); + ImGui::Text("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport->ID, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport ? g.MouseLastHoveredViewport->ID : 0); ImGui::TreePop(); } From 8497948ba0b1a868713b1bfe2ea204befe90735e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 13 Dec 2018 13:22:10 +0100 Subject: [PATCH 023/195] Comments, minor tweaks. --- imgui.cpp | 4 ++-- imgui.h | 25 +++++++++++++++---------- imgui_demo.cpp | 4 ++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 652c4095..6fcbc85d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6523,7 +6523,7 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) int n = 0; if (ref_window) { - for (n = 0; n < g.OpenPopupStack.Size; n++) + for (; n < g.OpenPopupStack.Size; n++) { ImGuiPopupRef& popup = g.OpenPopupStack[n]; if (!popup.Window) @@ -6540,7 +6540,7 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) break; } } - if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below + if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below ClosePopupToLevel(n); } diff --git a/imgui.h b/imgui.h index d43752f8..ebe00640 100644 --- a/imgui.h +++ b/imgui.h @@ -222,9 +222,12 @@ namespace ImGui // Windows // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. // - You may append multiple times to the same window during the same frame. - // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, which clicking will set the boolean to false when clicked. - // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. - // Always call a matching End() for each Begin() call, regardless of its return value [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, + // which clicking will set the boolean to false when clicked. + // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting + // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! + // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + // - Note that the bottom of window stack always contains a window called "Debug". IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API void End(); @@ -238,6 +241,7 @@ namespace ImGui IMGUI_API void EndChild(); // Windows Utilities + // "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into. IMGUI_API bool IsWindowAppearing(); IMGUI_API bool IsWindowCollapsed(); IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. @@ -485,7 +489,7 @@ namespace ImGui 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)); IMGUI_API void PlotHistogram(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)); - // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) + // Widgets: Value() Helpers. Simple shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) IMGUI_API void Value(const char* prefix, bool b); IMGUI_API void Value(const char* prefix, int v); IMGUI_API void Value(const char* prefix, unsigned int v); @@ -561,12 +565,13 @@ namespace ImGui IMGUI_API void PopClipRect(); // Focus, Activation - // (Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item") + // Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. // Item/Widgets Utilities - // See Demo Window under "Widgets->Querying Status" for an interactive visualization of many of those functions. + // Most of the functions are referring to the last/previous item we submitted. + // See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? @@ -586,8 +591,8 @@ namespace ImGui // 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. - IMGUI_API double GetTime(); - IMGUI_API int GetFrameCount(); + IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. + IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. IMGUI_API ImDrawList* GetOverlayDrawList(); // this draw list will be the last rendered one, useful to quickly draw overlays shapes/text IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances IMGUI_API const char* GetStyleColorName(ImGuiCol idx); @@ -624,8 +629,8 @@ namespace ImGui IMGUI_API void ResetMouseDragDelta(int button = 0); // IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type - IMGUI_API void CaptureKeyboardFromApp(bool capture = true); // manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. - IMGUI_API void CaptureMouseFromApp(bool capture = true); // manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). + IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. + IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) IMGUI_API const char* GetClipboardText(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f173221f..d9eabfd3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3431,7 +3431,7 @@ static void ShowExampleAppLog(bool* p_open) static void ShowExampleAppLayout(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); - if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar)) + if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) { if (ImGui::BeginMenuBar()) { @@ -3701,7 +3701,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) if (corner != -1) ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background - if (ImGui::Begin("Example: Simple Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) + if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) { ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); ImGui::Separator(); From 587506dd575cb230bf7379be4ed9b233f75dfabd Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 14 Dec 2018 11:27:02 +0100 Subject: [PATCH 024/195] Tests: Changed prototype of ImGuiTestEngineHook_ItemAdd to match functions called in same spot. Made ButtonBehavior submit fallback item info if ItemAdd() was not called (for resize grips, resize borders, scrollbar, columns, etc.) --- imgui.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6fcbc85d..447f78a1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2630,7 +2630,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_ItemAdd(id, bb); + ImGuiTestEngineHook_ItemAdd(bb, id); #endif // Clipping test diff --git a/imgui_internal.h b/imgui_internal.h index 033888ef..ab0691d1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1427,7 +1427,7 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch #ifdef IMGUI_ENABLE_TEST_ENGINE extern void ImGuiTestEngineHook_PreNewFrame(); extern void ImGuiTestEngineHook_PostNewFrame(); -extern void ImGuiTestEngineHook_ItemAdd(ImGuiID id, const ImRect& bb); +extern void ImGuiTestEngineHook_ItemAdd(const ImRect& bb, ImGuiID id); extern void ImGuiTestEngineHook_ItemInfo(ImGuiID id, const char* label, int flags); #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(_ID, _LABEL, _FLAGS) // Register status flags #else diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 672fa5ca..3bc83441 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -396,6 +396,11 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window) g.HoveredWindow = window; +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (window->DC.LastItemId != id) + ImGuiTestEngineHook_ItemAdd(bb, id); +#endif + bool pressed = false; bool hovered = ItemHoverable(bb, id); From 5d20da1b3622864eeb06b726cfb27cc2e19c486d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 14 Dec 2018 11:59:44 +0100 Subject: [PATCH 025/195] Viewport, DPI: Now using DpiScale from the ImGuiPlatformMonitor array instead of calling Platform_GetWindowDpiScale() before the platform window creation. Might even tentatively see if things work out without Platform_GetWindowDpiScale. (#1676) --- examples/imgui_impl_win32.cpp | 20 ++++---------------- examples/imgui_impl_win32.h | 7 +++---- imgui.cpp | 10 ++++++---- imgui.h | 8 ++++---- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 63c27046..cf88c823 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -366,7 +366,7 @@ void ImGui_ImplWin32_EnableDpiAwareness() float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) { UINT xdpi = 96, ydpi = 96; - if (IsWindows8Point1OrGreater()) + if (::IsWindows8Point1OrGreater()) { static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor")) @@ -389,13 +389,6 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); } -float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2) -{ - RECT viewport_rect = { (LONG)x1, (LONG)y1, (LONG)x2, (LONG)y2 }; - HMONITOR monitor = ::MonitorFromRect(&viewport_rect, MONITOR_DEFAULTTONEAREST); - return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); -} - //-------------------------------------------------------------------------------------------------------- // IME (Input Method Editor) basic support for e.g. Asian language users //-------------------------------------------------------------------------------------------------------- @@ -589,13 +582,8 @@ static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha) static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport) { ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData; - if (data && data->Hwnd) - return ImGui_ImplWin32_GetDpiScaleForHwnd(data->Hwnd); - - // The first frame a viewport is created we don't have a window yet - return ImGui_ImplWin32_GetDpiScaleForRect( - (int)(viewport->Pos.x), (int)(viewport->Pos.y), - (int)(viewport->Pos.x + viewport->Size.x), (int)(viewport->Pos.y + viewport->Size.y)); + IM_ASSERT(data->Hwnd != 0); + return ImGui_ImplWin32_GetDpiScaleForHwnd(data->Hwnd); } // FIXME-DPI: Testing DPI related ideas @@ -706,7 +694,7 @@ static void ImGui_ImplWin32_InitPlatformInterface() platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized; platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle; platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha; - platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; + platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI #if HAS_WIN32_IME platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos; diff --git a/examples/imgui_impl_win32.h b/examples/imgui_impl_win32.h index 5f163152..b7c9d819 100644 --- a/examples/imgui_impl_win32.h +++ b/examples/imgui_impl_win32.h @@ -16,10 +16,9 @@ IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); // DPI-related helpers (which run and compile without requiring 8.1 or 10, neither Windows version, neither associated SDK) -IMGUI_API void ImGui_ImplWin32_EnableDpiAwareness(); -IMGUI_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd -IMGUI_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor -IMGUI_API float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2); +IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor // Handler for Win32 messages, update mouse/keyboard data. // You may or not need this for your implementation, but it can serve as reference for handling inputs. diff --git a/imgui.cpp b/imgui.cpp index a7db3b7d..d499d1d8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7376,8 +7376,10 @@ static void ImGui::UpdateViewports() // Update DPI scale float new_dpi_scale; - if (g.PlatformIO.Platform_GetWindowDpiScale) + if (g.PlatformIO.Platform_GetWindowDpiScale && platform_funcs_available) new_dpi_scale = g.PlatformIO.Platform_GetWindowDpiScale(viewport); + else if (viewport->PlatformMonitor != -1) + new_dpi_scale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale; else new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f; if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale) @@ -7490,10 +7492,10 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport->Pos.x + viewport->Size.x); g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport->Pos.y + viewport->Size.y); - // Request an initial DpiScale before the OS platform window creation + // Store initial DpiScale before the OS platform window creation, based on expected monitor data. // This is so we can select an appropriate font size on the first frame of our window lifetime - if (g.PlatformIO.Platform_GetWindowDpiScale) - viewport->DpiScale = g.PlatformIO.Platform_GetWindowDpiScale(viewport); + if (viewport->PlatformMonitor != -1) + viewport->DpiScale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale; } viewport->Window = window; diff --git a/imgui.h b/imgui.h index fc687fbc..f70b465b 100644 --- a/imgui.h +++ b/imgui.h @@ -2124,13 +2124,13 @@ struct ImFont // - if you are new to dear imgui and trying to integrate it into your engine, you should probably ignore this for now. //----------------------------------------------------------------------------- -// (Optional) Represent the bounds of each connected monitor/display -// Dear ImGui only uses this to clamp the position of popups and tooltips so they don't straddle multiple monitors. +// (Optional) Represent the bounds of each connected monitor/display and their DPI +// This is used for: multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors. struct ImGuiPlatformMonitor { ImVec2 MainPos, MainSize; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) ImVec2 WorkPos, WorkSize; // (Optional) Coordinates without task bars / side bars / menu bars. imgui uses this to avoid positioning popups/tooltips inside this region. - float DpiScale; + float DpiScale; // 1.0f = 96 DPI ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0,0); DpiScale = 1.0f; } }; @@ -2165,7 +2165,7 @@ struct ImGuiPlatformIO void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // (Optional) Setup window transparency void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render (platform side) void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (platform side) - float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. IMPORTANT: this will be called _before_ the window is created, in which case the implementation is expected to use the viewport->Pos/Size fields to estimate DPI value. + float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Called during Begin() every time the viewport we are outputting into changes, so back-end has a chance to swap fonts to adjust style. void (*Platform_SetImeInputPos)(ImGuiViewport* vp, ImVec2 pos); // (Optional) Set IME (Input Method Editor, e.g. for Asian languages) input position, so text preview appears over the imgui input box. int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For Renderer to call into Platform code From f1c75964098f81cf66c0d42653dc258ce5eaaf02 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 14 Dec 2018 16:24:59 +0100 Subject: [PATCH 026/195] Internals: Popup related comments. Renamed the misleading internal ClosePopup() function. Added bool* test to BeginPopupModal in demo. --- imgui.cpp | 35 +++++++++++++++++------------------ imgui.h | 18 +++++++++++++----- imgui_demo.cpp | 12 +++++++++--- imgui_internal.h | 3 +-- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 447f78a1..da10a1e6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6520,12 +6520,13 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. // Don't close our own child popup windows. - int n = 0; + int popup_count_to_keep = 0; if (ref_window) { - for (; n < g.OpenPopupStack.Size; n++) + // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) + for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) { - ImGuiPopupRef& popup = g.OpenPopupStack[n]; + ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep]; if (!popup.Window) continue; IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); @@ -6533,15 +6534,19 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) continue; // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow) - bool has_focus = false; - for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) - has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow); - if (!has_focus) + bool popup_or_descendent_has_focus = false; + for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++) + if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow) + popup_or_descendent_has_focus = true; + if (!popup_or_descendent_has_focus) break; } } - if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below - ClosePopupToLevel(n); + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + { + //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); + ClosePopupToLevel(popup_count_to_keep); + } } void ImGui::ClosePopupToLevel(int remaining) @@ -6556,14 +6561,6 @@ void ImGui::ClosePopupToLevel(int remaining) g.OpenPopupStack.resize(remaining); } -void ImGui::ClosePopup(ImGuiID id) -{ - if (!IsPopupOpen(id)) - return; - ImGuiContext& g = *GImGui; - ClosePopupToLevel(g.OpenPopupStack.Size - 1); -} - // Close the popup we have begin-ed into. void ImGui::CloseCurrentPopup() { @@ -6610,6 +6607,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); } +// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. +// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; @@ -6632,7 +6631,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla { EndPopup(); if (is_open) - ClosePopup(id); + ClosePopupToLevel(g.CurrentPopupStack.Size); return false; } return is_open; diff --git a/imgui.h b/imgui.h index ebe00640..b4ea2d89 100644 --- a/imgui.h +++ b/imgui.h @@ -226,7 +226,8 @@ namespace ImGui // which clicking will set the boolean to false when clicked. // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! - // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] + // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. + // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] // - Note that the bottom of window stack always contains a window called "Debug". IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API void End(); @@ -511,7 +512,14 @@ namespace ImGui IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip(). IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); - // Popups + // Popups, Modals + // The properties of popups windows are: + // - They block normal mouse hovering detection outside them. (*) + // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. + // User can manipulate the visibility state by calling OpenPopup(). + // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. + // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! @@ -520,11 +528,11 @@ namespace ImGui IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened. - IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open + IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current begin-ed level of the popup stack. IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. // Columns - // You can also use SameLine(pos_x) for simplified columns. The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) + // You can also use SameLine(pos_x) to mimic simplified columns. The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API int GetColumnIndex(); // get current column index @@ -543,7 +551,7 @@ namespace ImGui IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. - IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty + IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty (stdout) IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard IMGUI_API void LogFinish(); // stop logging (close file, etc.) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d9eabfd3..3e382ddd 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1981,12 +1981,13 @@ static void ShowDemoWindowPopups() if (!ImGui::CollapsingHeader("Popups & Modal windows")) return; - // Popups are windows with a few special properties: + // The properties of popups windows are: // - They block normal mouse hovering detection outside them. (*) // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls. + // User can manipulate the visibility state by calling OpenPopup(). // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup. - // Those three properties are intimately connected. The library needs to hold their visibility state because it can close popups at any time. + // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time. // Typical use for regular windows: // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); @@ -2115,6 +2116,7 @@ static void ShowDemoWindowPopups() if (ImGui::Button("Delete..")) ImGui::OpenPopup("Delete?"); + if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); @@ -2147,7 +2149,11 @@ static void ShowDemoWindowPopups() if (ImGui::Button("Add another modal..")) ImGui::OpenPopup("Stacked 2"); - if (ImGui::BeginPopupModal("Stacked 2")) + + // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup. + // Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here. + bool dummy_open = true; + if (ImGui::BeginPopupModal("Stacked 2", &dummy_open)) { ImGui::Text("Hello from Stacked The Second!"); if (ImGui::Button("Close")) diff --git a/imgui_internal.h b/imgui_internal.h index ab0691d1..aa5b5c38 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1297,10 +1297,9 @@ namespace ImGui // Popups, Modals, Tooltips IMGUI_API void OpenPopupEx(ImGuiID id); - IMGUI_API void ClosePopup(ImGuiID id); IMGUI_API void ClosePopupToLevel(int remaining); IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window); - IMGUI_API bool IsPopupOpen(ImGuiID id); + IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack! IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); IMGUI_API ImGuiWindow* GetFrontMostPopupModal(); From f6f5c511063d53256fadaf1ce0575a3d684a53ba Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 14 Dec 2018 18:42:11 +0100 Subject: [PATCH 027/195] Internals: Popups: EndMenu() calls ClosePopupToLevel(g.CurrentPopupStack.Size) which is more correct. --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3bc83441..d3edd7bf 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5687,14 +5687,14 @@ bool ImGui::BeginMenu(const char* label, bool enabled) void ImGui::EndMenu() { - // Nav: When a left move request _within our child menu_ failed, close the menu. + // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) { - ClosePopupToLevel(g.OpenPopupStack.Size - 1); + ClosePopupToLevel(g.CurrentPopupStack.Size); NavMoveRequestCancel(); } From 65dac021712f99ba954392734ceafe43392efe59 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 14 Dec 2018 18:44:17 +0100 Subject: [PATCH 028/195] Internals: Popups: Renamed CurrentPopupStack to BeginPopupStack which is much less ambiguous. --- imgui.cpp | 38 +++++++++++++++++++------------------- imgui_internal.h | 2 +- imgui_widgets.cpp | 14 +++++++------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index da10a1e6..3d019dbc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3299,7 +3299,7 @@ void ImGui::NewFrame() // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. g.CurrentWindowStack.resize(0); - g.CurrentPopupStack.resize(0); + g.BeginPopupStack.resize(0); ClosePopupsOverWindow(g.NavWindow); // Create implicit/fallback window - which we will only render it if the user has added something to it. @@ -3373,7 +3373,7 @@ void ImGui::Shutdown(ImGuiContext* context) g.StyleModifiers.clear(); g.FontStack.clear(); g.OpenPopupStack.clear(); - g.CurrentPopupStack.clear(); + g.BeginPopupStack.clear(); g.DrawDataBuilder.ClearFreeMemory(); g.OverlayDrawList.ClearFreeMemory(); g.PrivateClipboard.clear(); @@ -3942,8 +3942,8 @@ ImVec2 ImGui::GetMousePos() ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() { ImGuiContext& g = *GImGui; - if (g.CurrentPopupStack.Size > 0) - return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos; return g.IO.MousePos; } @@ -4224,7 +4224,7 @@ static void CheckStacksSize(ImGuiWindow* window, bool write) short* p_backup = &window->DC.StackSizesBackup[0]; { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop() { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup() - { int current = g.CurrentPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() + { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup() // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor() { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar() @@ -4638,7 +4638,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0); if (flags & ImGuiWindowFlags_Popup) { - ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; + ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed window_just_activated_by_user |= (window != popup_ref.Window); } @@ -4652,9 +4652,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) CheckStacksSize(window, true); if (flags & ImGuiWindowFlags_Popup) { - ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; + ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; popup_ref.Window = window; - g.CurrentPopupStack.push_back(popup_ref); + g.BeginPopupStack.push_back(popup_ref); window->PopupId = popup_ref.PopupId; } @@ -4829,7 +4829,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->AutoPosLastDirection = ImGuiDir_None; if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) - window->Pos = g.CurrentPopupStack.back().OpenPopupPos; + window->Pos = g.BeginPopupStack.back().OpenPopupPos; } // Position child window @@ -5232,7 +5232,7 @@ void ImGui::End() // Pop from window stack g.CurrentWindowStack.pop_back(); if (window->Flags & ImGuiWindowFlags_Popup) - g.CurrentPopupStack.pop_back(); + g.BeginPopupStack.pop_back(); CheckStacksSize(window, false); SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); } @@ -6428,13 +6428,13 @@ void ImGui::SetTooltip(const char* fmt, ...) bool ImGui::IsPopupOpen(ImGuiID id) { ImGuiContext& g = *GImGui; - return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; } bool ImGui::IsPopupOpen(const char* str_id) { ImGuiContext& g = *GImGui; - return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); } ImGuiWindow* ImGui::GetFrontMostPopupModal() @@ -6461,7 +6461,7 @@ void ImGui::OpenPopupEx(ImGuiID id) { ImGuiContext& g = *GImGui; ImGuiWindow* parent_window = g.CurrentWindow; - int current_stack_size = g.CurrentPopupStack.Size; + int current_stack_size = g.BeginPopupStack.Size; ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. popup_ref.PopupId = id; popup_ref.Window = NULL; @@ -6565,8 +6565,8 @@ void ImGui::ClosePopupToLevel(int remaining) void ImGui::CloseCurrentPopup() { ImGuiContext& g = *GImGui; - int popup_idx = g.CurrentPopupStack.Size - 1; - if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + int popup_idx = g.BeginPopupStack.Size - 1; + if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) return; while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) popup_idx--; @@ -6584,7 +6584,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) char name[20]; if (extra_flags & ImGuiWindowFlags_ChildMenu) - ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth else ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame @@ -6598,7 +6598,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; - if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance { g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values return false; @@ -6631,7 +6631,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla { EndPopup(); if (is_open) - ClosePopupToLevel(g.CurrentPopupStack.Size); + ClosePopupToLevel(g.BeginPopupStack.Size); return false; } return is_open; @@ -6641,7 +6641,7 @@ void ImGui::EndPopup() { ImGuiContext& g = *GImGui; (void)g; IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls - IM_ASSERT(g.CurrentPopupStack.Size > 0); + IM_ASSERT(g.BeginPopupStack.Size > 0); // Make all menus and popups wrap around for now, may need to expose that policy. NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY); diff --git a/imgui_internal.h b/imgui_internal.h index aa5b5c38..53408f12 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -743,7 +743,7 @@ struct ImGuiContext ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() ImVector OpenPopupStack; // Which popups are open (persistent) - ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) + ImVector BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions ImGuiCond NextTreeNodeOpenCond; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d3edd7bf..367c4df9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1337,7 +1337,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF } char name[16]; - ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth // Peak into expected window size so we can position it if (ImGuiWindow* popup_window = FindWindowByName(name)) @@ -5563,7 +5563,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) bool pressed; bool menu_is_open = IsPopupOpen(id); - bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back()); + bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back()); ImGuiWindow* backed_nav_window = g.NavWindow; if (menuset_is_open) g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) @@ -5604,9 +5604,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled) { // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. bool moving_within_opened_triangle = false; - if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar)) + if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar)) { - if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window) + if (ImGuiWindow* next_window = g.OpenPopupStack[g.BeginPopupStack.Size].Window) { ImRect next_window_rect = next_window->Rect(); ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; @@ -5657,11 +5657,11 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' want_close = true; if (want_close && IsPopupOpen(id)) - ClosePopupToLevel(g.CurrentPopupStack.Size); + ClosePopupToLevel(g.BeginPopupStack.Size); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); - if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size) + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) { // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. OpenPopup(label); @@ -5694,7 +5694,7 @@ void ImGui::EndMenu() ImGuiWindow* window = g.CurrentWindow; if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) { - ClosePopupToLevel(g.CurrentPopupStack.Size); + ClosePopupToLevel(g.BeginPopupStack.Size); NavMoveRequestCancel(); } From 1a6ec208cc9e36127408a45b7954dc0cc74ec67b Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 18 Dec 2018 11:50:14 +0100 Subject: [PATCH 029/195] Docs: various updates, rewording, clarifying the purpose of a PR. --- .github/CONTRIBUTING.md | 1 + .github/pull_request_template.md | 1 + docs/README.md | 46 ++++++++++++++++++++------------ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4fe220b9..5bbd8e15 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -33,6 +33,7 @@ You may use the Issue Tracker to submit bug reports, feature requests or suggest If you have been using dear imgui for a while or have been using C/C++ for several years or have demonstrated good behavior here, it is ok to not fullfill every item to the letter. Those are guidelines and experienced users or members of the community will know which information are useful in a given context. ## How to create an Pull Request +- Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. - When adding a feature, please describe the usage context (how you intend to use it, why you need it, etc.). - When fixing a warning or compilation problem, please post the compiler log and specify the version and OS you are using. - Try to attach screenshots to clarify the context and demonstrate the feature at a glance. You can drag pictures/files here (prefer github attachments over 3rd party hosting). diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 05c68ea6..65ebcf24 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,4 +1,5 @@ - Please read https://github.com/ocornut/imgui/blob/master/.github/CONTRIBUTING.md +- Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. - When adding a feature, please describe the usage context (how you intend to use it, why you need it, etc.). - When adding a feature, try to attach screenshots/gifs to clarify the context and demonstrate the feature at a glance. - When fixing a warning or compilation problem, post the compiler log and specify the version and OS you are using. diff --git a/docs/README.md b/docs/README.md index bd711799..3507d192 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,13 +3,16 @@ dear imgui, [![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui) [![Coverity Status](https://scan.coverity.com/projects/4720/badge.svg)](https://scan.coverity.com/projects/4720) -_(This library is free but needs your support to sustain its development. There are many desirable features and maintenance ahead. If you are an individual using dear imgui, please consider donating via Patreon or PayPal. If your company is using dear imgui, please consider financial support (e.g. sponsoring a few weeks/months of development). I can invoice for technical support, custom development etc. Email: omarcornut at gmail)._ +_(This library is free as in freedom, but needs your support to sustain its development. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for invoiced financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal.)_ -Monthly donations via Patreon: -
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) +Individuals/hobbyists: support continued maintenance and development via the monthly Patreon: +
 [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) -One-off donations via PayPal: -
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) +Individuals/hobbyists: support continued maintenance and development via PayPal: +
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) + +Businesses: support continued maintenance and development via support contracts or sponsoring a few weeks/months of development: +
  _E-mail: omarcornut at gmail dot com_ Dear ImGui is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies). @@ -158,7 +161,7 @@ Some of the goals for 2019 are: - Finish work on docking, tabs. (see [#2109](https://github.com/ocornut/imgui/issues/2109), public branch looking for feedback) - Finish work on multiple viewports / multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), public branch looking for feedback) - Finish work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787)) -- Add an automation and testing system, both to test the library and end-user apps. +- Add an automation and testing system, both to test the library and end-user apps. (see [#435](https://github.com/ocornut/imgui/issues/435)) - Make Columns better. (they are currently pretty terrible!) - Make the examples look better, improve styles, improve font support, make the examples hi-DPI aware. @@ -291,30 +294,39 @@ There is an auto-generated [c-api for Dear ImGui (cimgui)](https://github.com/ci Support dear imgui ------------------ +**How can I help?** + +- You may participate in the Discourse and GitHub [issues trackers](https://github.com/ocornut/imgui/issues). +- You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. +- See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the Wiki for some more ideas. +- Convince your company to financially support this project. + **How can I help financing further development of Dear ImGui?** -Your contributions are keeping the library alive. If you are an individual using dear imgui, please consider donating to enable me to spend more time improving the library. +Your contributions are keeping this project alive. The library is free as in freedom, but continued maintenance and development are a full-time endeavor. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for invoiced financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal. Thank you! + +Individuals/hobbyists: support continued maintenance and development via the monthly Patreon: +
 [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) -Monthly donations via Patreon: -
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) +Individuals/hobbyists: support continued maintenance and development via PayPal: +
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) -One-off donations via PayPal: -
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) +Businesses: support continued maintenance and development via support contracts or sponsoring a few weeks/months of development: +
  _E-mail: omarcornut at gmail dot com_ -Ongoing dear imgui development is financially supported on [**Patreon**](http://www.patreon.com/imgui) and by private sponsors. -If your company uses dear imgui, please consider financial support (e.g. sponsoring a few weeks/months of development. I can also invoice for private support, custom development etc. contact me for details: omarcornut at gmail). Thanks! +Ongoing dear imgui development is financially supported by users and private sponsors (past and present): **Platinum-chocolate sponsors** -- Blizzard Entertainment. +- **Blizzard Entertainment**. **Double-chocolate sponsors** -- Media Molecule, Mobigame, Insomniac Games, Aras Pranckevičius, Lizardcube, Greggman, DotEmu, Nadeo, Supercell, Runner. +- Media Molecule, Mobigame, Insomniac Games, Aras Pranckevičius, Lizardcube, Greggman, DotEmu, Nadeo, Supercell, Runner, Aiden Koss. **Salty caramel supporters** -- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Recognition Robotics, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko, Mercury Labs, Singularity Demo Group, Mischa Alff, Sebastien Ronsse, Lionel Landwerlin, Nikolay Ivanov, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts. +- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Recognition Robotics, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko, Mercury Labs, Singularity Demo Group, Mischa Alff, Sebastien Ronsse, Lionel Landwerlin, Nikolay Ivanov, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts, Rainway inc. **Caramel supporters** -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, Kit framework, Josh Faust, Martin Donlon, Quinton, Felix, Andrew Belt, Codecat, Cort Stratton, Claudio Canepa, Doug McNabb, Emmanuel Julien, Guillaume Chereau, Jeffrey Slutter, Jeremiah Deckard, r-lyeh, Roger Clark, Nekith, Joshua Fisher, Malte Hoffmann, Mustafa Karaalioglu, Merlyn Morgan-Graham, Per Vognsen, Fabian Giesen, Jan Staubach, Matt Hargett, John Shearer, Jesse Chounard, kingcoopa, Miloš Tošić, Jonas Bernemann, Johan Andersson, Nathan Hartman, Michael Labbe, Tomasz Golebiowski, Louis Schnellbach, Felipe Alfonso, Jimmy Andrews, Bojan Endrovski, Robin Berg Pettersen, Rachel Crawford, Edsel Malasig, Andrew Johnson, Sean Hunter, Jordan Mellow, Nefarius Software Solutions, Laura Wieme, Robert Nix, Mick Honey, Astrofra, Jonas Lehmann, Steven Kah Hien Wong, Bartosz Bielecki, Oscar Penas, A M, Liam Moynihan, Artometa. +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, Kit framework, Josh Faust, Martin Donlon, Quinton, Felix, Andrew Belt, Codecat, Cort Stratton, Claudio Canepa, Doug McNabb, Emmanuel Julien, Guillaume Chereau, Jeffrey Slutter, Jeremiah Deckard, r-lyeh, Roger Clark, Nekith, Joshua Fisher, Malte Hoffmann, Mustafa Karaalioglu, Merlyn Morgan-Graham, Per Vognsen, Fabian Giesen, Jan Staubach, Matt Hargett, John Shearer, Jesse Chounard, kingcoopa, Miloš Tošić, Jonas Bernemann, Johan Andersson, Nathan Hartman, Michael Labbe, Tomasz Golebiowski, Louis Schnellbach, Felipe Alfonso, Jimmy Andrews, Bojan Endrovski, Robin Berg Pettersen, Rachel Crawford, Edsel Malasig, Andrew Johnson, Sean Hunter, Jordan Mellow, Nefarius Software Solutions, Laura Wieme, Robert Nix, Mick Honey, Astrofra, Jonas Lehmann, Steven Kah Hien Wong, Bartosz Bielecki, Oscar Penas, A M, Liam Moynihan, Artometa, Mark Lee, Dimitri Diakopoulos. And all other supporters; THANK YOU! (Please contact me if you would like to be added or removed from this list) From 510ca373a2286a498349d971318a6bbc98324864 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 18 Dec 2018 14:21:10 +0100 Subject: [PATCH 030/195] Moved setting up NavHideHighlightOneFrame from lower-level ClosePopupToLevel() to CloseCurrentPopup() with an explanation. (Followup on 68d3e139a74ed9d7cad4abb0f36466544ef24620) --- imgui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 3d019dbc..637bc5cd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6557,7 +6557,6 @@ void ImGui::ClosePopupToLevel(int remaining) if (g.NavLayer == 0) focus_window = NavRestoreLastChildNavWindow(focus_window); FocusWindow(focus_window); - focus_window->DC.NavHideHighlightOneFrame = true; g.OpenPopupStack.resize(remaining); } @@ -6571,6 +6570,12 @@ void ImGui::CloseCurrentPopup() while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) popup_idx--; ClosePopupToLevel(popup_idx); + + // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. + // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. + // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; } bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) From ae76a1fda7e0caccad70b03933dcdf0199810d88 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 18 Dec 2018 14:58:35 +0100 Subject: [PATCH 031/195] Window, Focus, Popup: Fixed an issue where closing a popup by clicking another window with the _NoMove flag would refocus the parent window of the popup instead of the newly clicked window. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 26 +++++++++++++++++++------- imgui_internal.h | 2 +- imgui_widgets.cpp | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9b303233..b8419caa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Other Changes: (It does not provide the docking/splitting/merging of windows available in the Docking branch) - Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience to avoid using the ### operator. +- Window, Focus, Popup: Fixed an issue where closing a popup by clicking another window with the _NoMove flag would refocus + the parent window of the popup instead of the newly clicked window. - Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. - Window: Contents size is preserved while a window contents is hidden (unless it is hidden for resizing purpose). - Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that diff --git a/imgui.cpp b/imgui.cpp index 637bc5cd..caa85265 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6545,19 +6545,31 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window) if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below { //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); - ClosePopupToLevel(popup_count_to_keep); + ClosePopupToLevel(popup_count_to_keep, false); } } -void ImGui::ClosePopupToLevel(int remaining) +void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under) { IM_ASSERT(remaining >= 0); ImGuiContext& g = *GImGui; ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow; - if (g.NavLayer == 0) - focus_window = NavRestoreLastChildNavWindow(focus_window); - FocusWindow(focus_window); g.OpenPopupStack.resize(remaining); + + // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely. + // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing. + // The current code will set focus to the parent of the popup window which is incorrect. + // It rarely manifested until now because UpdateMouseMovingWindow() would call FocusWindow() again on the clicked window, + // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again. + // However if the clicked window has the _NoMove flag set we would be left with B focused. + // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway, + // but we should inspect and fix this properly. + if (apply_focus_to_window_under) + { + if (g.NavLayer == 0) + focus_window = NavRestoreLastChildNavWindow(focus_window); + FocusWindow(focus_window); + } } // Close the popup we have begin-ed into. @@ -6569,7 +6581,7 @@ void ImGui::CloseCurrentPopup() return; while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) popup_idx--; - ClosePopupToLevel(popup_idx); + ClosePopupToLevel(popup_idx, true); // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. @@ -6636,7 +6648,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla { EndPopup(); if (is_open) - ClosePopupToLevel(g.BeginPopupStack.Size); + ClosePopupToLevel(g.BeginPopupStack.Size, true); return false; } return is_open; diff --git a/imgui_internal.h b/imgui_internal.h index 53408f12..60704564 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1297,7 +1297,7 @@ namespace ImGui // Popups, Modals, Tooltips IMGUI_API void OpenPopupEx(ImGuiID id); - IMGUI_API void ClosePopupToLevel(int remaining); + IMGUI_API void ClosePopupToLevel(int remaining, bool apply_focus_to_window_under); IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window); IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack! IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 367c4df9..367b9bb6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5657,7 +5657,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' want_close = true; if (want_close && IsPopupOpen(id)) - ClosePopupToLevel(g.BeginPopupStack.Size); + ClosePopupToLevel(g.BeginPopupStack.Size, true); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); @@ -5694,7 +5694,7 @@ void ImGui::EndMenu() ImGuiWindow* window = g.CurrentWindow; if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) { - ClosePopupToLevel(g.BeginPopupStack.Size); + ClosePopupToLevel(g.BeginPopupStack.Size, true); NavMoveRequestCancel(); } From ca953f0fee93f7947f804018493fc34cac8538d4 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 18 Dec 2018 15:11:11 +0100 Subject: [PATCH 032/195] Fix merge issue on master. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index caa85265..5676ae3b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7374,7 +7374,7 @@ static void ImGui::NavUpdate() { // Close open popup/menu if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) - ClosePopupToLevel(g.OpenPopupStack.Size - 1); + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); } else if (g.NavLayer != 0) { From 84d1ce39584161dfd027613b0defe305637f3867 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 18 Dec 2018 16:16:17 +0100 Subject: [PATCH 033/195] Tidying up README, moved entries to FAQ, updated screenshots, removed comma in title. --- docs/README.md | 55 +++++++++++++++----------------------------------- imgui.cpp | 20 ++++++++++++++++-- imgui_demo.cpp | 2 +- 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/docs/README.md b/docs/README.md index 3507d192..e396a108 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -dear imgui, +dear imgui ===== [![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui) [![Coverity Status](https://scan.coverity.com/projects/4720/badge.svg)](https://scan.coverity.com/projects/4720) @@ -6,12 +6,12 @@ dear imgui, _(This library is free as in freedom, but needs your support to sustain its development. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for invoiced financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal.)_ Individuals/hobbyists: support continued maintenance and development via the monthly Patreon: -
 [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) +
  [![Patreon](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/patreon_01.png)](http://www.patreon.com/imgui) Individuals/hobbyists: support continued maintenance and development via PayPal:
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) -Businesses: support continued maintenance and development via support contracts or sponsoring a few weeks/months of development: +Businesses: support continued maintenance and development via support contracts or sponsoring:
  _E-mail: omarcornut at gmail dot com_ Dear ImGui is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies). @@ -177,33 +177,17 @@ User screenshots:
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 onward)
Also see the [Mega screenshots](https://github.com/ocornut/imgui/issues/1273) for an idea of the available features. -Various tools +Custom engine [![screenshot game](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v149/gallery_TheDragonsTrap-01-thumb.jpg)](https://cloud.githubusercontent.com/assets/8225057/20628927/33e14cac-b329-11e6-80f6-9524e93b048a.png) +Custom engine [![screenshot tool](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/editor_white_preview.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/editor_white.png) -![screenshot demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/v160-misc-classic.png) +Demo window +![screenshot demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png) -[![screenshot profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler-880.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler.png) - -Dear ImGui can load TTF/OTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with: -Code: -```cpp -ImGuiIO& io = ImGui::GetIO(); -io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); -``` -```cpp -ImGui::Text(u8"こんにちは!テスト %d", 123); -if (ImGui::Button(u8"ロード")) -{ - // do stuff -} -ImGui::InputText("string", buf, IM_ARRAYSIZE(buf)); -ImGui::SliderFloat("float", &f, 0.0f, 1.0f); -``` -Result: -
![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/code_sample_02_jp.png) -
_(settings: Dark style (left), Light style (right) / Font: NotoSansCJKjp-Medium, 20px / Rounding: 5)_ +[Tracy Profiler](https://bitbucket.org/wolfpld/tracy) +![tracy profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/tracy_profiler.png) References ---------- @@ -246,7 +230,7 @@ You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issue See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can! -**Why the odd dual naming, "dear imgui" vs "ImGui"?** +**Why the odd dual naming, "Dear ImGui" vs "ImGui"?** The library started its life and is best known as "ImGui" only due to the fact that I didn't give it a proper name when I released it. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations. It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "dear imgui" that people can use to refer to this specific library in ambiguous situations. @@ -257,22 +241,15 @@ The library started its life and is best known as "ImGui" only due to the fact t
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
**How can I load multiple fonts?** -
**How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?** +
**How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?** ([example](https://github.com/ocornut/imgui/wiki/Loading-Font-Example))
**How can I use the drawing facilities without an Dear ImGui window? (using ImDrawList API)** +
**How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)**
**I integrated Dear ImGui in my engine and the text or lines are blurry..**
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?** See the FAQ in imgui.cpp for answers. -**How do you use Dear ImGui on a platform that may not have a mouse or keyboard?** - -You can control Dear ImGui with a gamepad, see the explanation in imgui.cpp about how to use the navigation feature (short version: map your gamepad inputs into the `io.NavInputs[]` array and set `io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad`). - -You can share your computer mouse seamlessly with your console/tablet/phone using [Synergy](http://synergy-project.org). This is the preferred solution for developer productivity. In particular, their [micro-synergy-client](https://github.com/symless/micro-synergy-client) repo there is _uSynergy.c_ sources for a small embeddable that you can use on any platform to connect to your host PC using Synergy 1.x. You may also use a third party solution such as [Remote ImGui](https://github.com/JordiRos/remoteimgui). - -For touch inputs, you can increase the hit box of widgets (via the _style.TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing for screen real-estate and precision. - **Can you create elaborate/serious tools with Dear ImGui?** Yes. People have written game editors, data browsers, debuggers, profilers and all sort of non-trivial tools with the library. In my experience the simplicity of the API is very empowering. Your UI runs close to your live data. Make the tools always-on and everybody in the team will be inclined to create new tools (as opposed to more "offline" UI toolkits where only a fraction of your team effectively creates tools). The list of sponsors below is also an indicator that serious game teams have been using the library. @@ -303,15 +280,15 @@ Support dear imgui **How can I help financing further development of Dear ImGui?** -Your contributions are keeping this project alive. The library is free as in freedom, but continued maintenance and development are a full-time endeavor. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for invoiced financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal. Thank you! +Your contributions are keeping this project alive. The library is free as in freedom, but continued maintenance and development are a full-time endeavor. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal. Thank you! Individuals/hobbyists: support continued maintenance and development via the monthly Patreon: -
 [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) +
  [![Patreon](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/patreon_01.png)](http://www.patreon.com/imgui) Individuals/hobbyists: support continued maintenance and development via PayPal:
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) -Businesses: support continued maintenance and development via support contracts or sponsoring a few weeks/months of development: +Businesses: support continued maintenance and development via support contracts or sponsoring:
  _E-mail: omarcornut at gmail dot com_ Ongoing dear imgui development is financially supported by users and private sponsors (past and present): @@ -336,7 +313,7 @@ Credits Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com). -I first discovered imgui principles at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple imgui implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it. +I first discovered the IMGUI paradigm at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it. Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license). diff --git a/imgui.cpp b/imgui.cpp index 5676ae3b..1daedf7c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -43,6 +43,7 @@ DOCUMENTATION - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) + - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad) - I integrated Dear ImGui in my engine and the text or lines are blurry.. - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - How can I help? @@ -818,8 +819,23 @@ CODE (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse) Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows. - - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData, - and then call your rendered code with your own ImDrawList or ImDrawData data. + - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create + your own ImDrawListSharedData, and then call your rendered code with your own ImDrawList or ImDrawData data. + + Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) + A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls". + (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad) + - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy) + This is the preferred solution for developer productivity. + In particular, the "micro-synergy-client" repository (https://github.com/symless/micro-synergy-client) has simple + and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect + to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer. + Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols. + - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends + the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine. + - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate + for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing + for screen real-estate and precision. Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3e382ddd..d89bba1f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1775,7 +1775,7 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Groups")) { - ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)"); + ShowHelpMarker("Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it."); ImGui::BeginGroup(); { ImGui::BeginGroup(); From 89ac0ea7c12081a84c0ac48ccf9c3ac8c86f6675 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 19 Dec 2018 11:12:02 +0100 Subject: [PATCH 034/195] Various user-facing comments --- imgui.cpp | 10 +++-- imgui.h | 118 +++++++++++++++++++++++++++++------------------------- 2 files changed, 70 insertions(+), 58 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1daedf7c..c3d6373e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3972,6 +3972,8 @@ bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID; } +// Return the delta from the initial clicking position. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. // NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window. ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) { @@ -6098,10 +6100,10 @@ ImVec2 ImGui::GetCursorScreenPos() return window->DC.CursorPos; } -void ImGui::SetCursorScreenPos(const ImVec2& screen_pos) +void ImGui::SetCursorScreenPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.CursorPos = screen_pos; + window->DC.CursorPos = pos; window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); } @@ -6139,12 +6141,12 @@ void ImGui::SetScrollY(float scroll_y) window->ScrollTargetCenterRatio.y = 0.0f; } -void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio) +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) { // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size ImGuiWindow* window = GetCurrentWindow(); IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); - window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y); + window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y); window->ScrollTargetCenterRatio.y = center_y_ratio; } diff --git a/imgui.h b/imgui.h index b4ea2d89..431646b8 100644 --- a/imgui.h +++ b/imgui.h @@ -242,7 +242,7 @@ namespace ImGui IMGUI_API void EndChild(); // Windows Utilities - // "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into. + // - "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into. IMGUI_API bool IsWindowAppearing(); IMGUI_API bool IsWindowCollapsed(); IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. @@ -283,8 +283,8 @@ namespace ImGui IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] - IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. - IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions. + IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions. // Parameters stacks (shared) IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font @@ -307,7 +307,7 @@ namespace ImGui IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) IMGUI_API void PopItemWidth(); IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position - IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets IMGUI_API void PopAllowKeyboardFocus(); @@ -315,24 +315,26 @@ namespace ImGui IMGUI_API void PopButtonRepeat(); // Cursor / Layout + // - By "cursor" we mean the current output position. + // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. - IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally - IMGUI_API void NewLine(); // undo a SameLine() - IMGUI_API void Spacing(); // add vertical spacing - IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size + IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. + IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. + IMGUI_API void Spacing(); // add vertical spacing. + IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 - IMGUI_API void BeginGroup(); // lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) - IMGUI_API void EndGroup(); - IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position - IMGUI_API float GetCursorPosX(); // " - IMGUI_API float GetCursorPosY(); // " - IMGUI_API void SetCursorPos(const ImVec2& local_pos); // " - IMGUI_API void SetCursorPosX(float x); // " - IMGUI_API void SetCursorPosY(float y); // " - IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position + IMGUI_API void BeginGroup(); // lock horizontal starting position + IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) + IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) + IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc. + IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: + IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. + 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& screen_pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] 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) @@ -340,16 +342,16 @@ namespace ImGui IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) // ID stack/scopes - // Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most - // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. - // You can also use the "##foobar" syntax within widget label to distinguish them from each others. - // In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, - // whereas "str_id" denote a string that is only used as an ID and not aimed to be displayed. - IMGUI_API void PushID(const char* str_id); // push identifier into the ID stack. IDs are hash of the entire stack! + // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most + // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, + // whereas "str_id" denote a string that is only used as an ID and not normally displayed. + IMGUI_API void PushID(const char* str_id); // push string identifier into the ID stack. IDs == hash of the entire stack! IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); - IMGUI_API void PushID(const void* ptr_id); - IMGUI_API void PushID(int int_id); - IMGUI_API void PopID(); + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack. + IMGUI_API void PushID(int int_id); // push integer into the ID stack. + IMGUI_API void PopID(); // pop from the ID stack. IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); IMGUI_API ImGuiID GetID(const void* ptr_id); @@ -370,7 +372,7 @@ namespace ImGui IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); // Widgets: Main - // Most widgets return true when the value has been changed or when pressed/selected + // - Most widgets return true when the value has been changed or when pressed/selected IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) @@ -385,18 +387,19 @@ namespace ImGui IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses // Widgets: Combo Box - // The new 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 new 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. 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); IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); - // Widgets: Drags (tip: ctrl+click on a drag box to input with keyboard. manually input values aren't clamped, can go off-bounds) - // For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x - // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. - // Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + // Widgets: Drags + // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); @@ -410,8 +413,9 @@ namespace ImGui IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f); IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f); - // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds) - // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // Widgets: Sliders + // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); @@ -428,7 +432,7 @@ namespace ImGui IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); // Widgets: Input with Keyboard - // If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h + // - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); @@ -444,7 +448,7 @@ namespace ImGui IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) - // Note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x + // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); @@ -453,7 +457,7 @@ namespace ImGui IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. // Widgets: Trees - // TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. + // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. IMGUI_API bool TreeNode(const char* label); IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to completely decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " @@ -474,10 +478,13 @@ namespace ImGui IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header // Widgets: Selectables + // - A selectable highlights when hovered, and can display another color when selected. + // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height 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. 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. @@ -490,7 +497,8 @@ namespace ImGui 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)); IMGUI_API void PlotHistogram(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)); - // Widgets: Value() Helpers. Simple shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) + // Widgets: Value() Helpers. + // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) IMGUI_API void Value(const char* prefix, bool b); IMGUI_API void Value(const char* prefix, int v); IMGUI_API void Value(const char* prefix, unsigned int v); @@ -532,7 +540,8 @@ namespace ImGui IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. // Columns - // You can also use SameLine(pos_x) to mimic simplified columns. The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) + // - You can also use SameLine(pos_x) to mimic simplified columns. + // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API int GetColumnIndex(); // get current column index @@ -550,7 +559,8 @@ namespace ImGui IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. - // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. + // Logging/Capture + // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty (stdout) IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard @@ -559,7 +569,7 @@ namespace ImGui IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) // Drag and Drop - // [BETA API] Missing Demo code. API may evolve! + // [BETA API] API may evolve! IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t size, ImGuiCond cond = 0);// type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! @@ -573,13 +583,13 @@ namespace ImGui IMGUI_API void PopClipRect(); // Focus, Activation - // Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" + // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. // Item/Widgets Utilities - // Most of the functions are referring to the last/previous item we submitted. - // See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. + // - Most of the functions are referring to the last/previous item we submitted. + // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? @@ -591,9 +601,9 @@ namespace ImGui IMGUI_API bool IsAnyItemHovered(); IMGUI_API bool IsAnyItemActive(); IMGUI_API bool IsAnyItemFocused(); - IMGUI_API ImVec2 GetItemRectMin(); // get bounding rectangle of last item, in screen space - IMGUI_API ImVec2 GetItemRectMax(); // " - IMGUI_API ImVec2 GetItemRectSize(); // get size of last item, in screen space + IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) + 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. // Miscellaneous Utilities @@ -633,7 +643,7 @@ namespace ImGui IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into - IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount since clicking. if lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position. This is locked and return 0.0f until the mouse moves past a distance threshold at least once. If lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API void ResetMouseDragDelta(int button = 0); // IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type @@ -645,16 +655,16 @@ namespace ImGui IMGUI_API void SetClipboardText(const char* text); // Settings/.Ini Utilities - // The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). - // Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. + // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). + // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. // Memory Utilities - // All those functions are not reliant on the current context. - // If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again. + // - All those functions are not reliant on the current context. + // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again. IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); IMGUI_API void* MemAlloc(size_t size); IMGUI_API void MemFree(void* ptr); From 6890e08bc5c9d00cae3af913e47c9daf017e0164 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 19 Dec 2018 15:19:31 +0100 Subject: [PATCH 035/195] Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. Demo tweak and adding some child window stuff --- docs/CHANGELOG.txt | 3 +++ docs/TODO.txt | 1 + imgui.cpp | 4 ++++ imgui_demo.cpp | 40 ++++++++++++++++++++++++++++++++-------- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b8419caa..edf16b60 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,9 +58,12 @@ Other Changes: it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. - Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) +- Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected + in the parent window, so there is no mismatch between the layout in parent and the position of the child window. - Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. - Demo: "Simple Layout" and "Style Editor" are now using tabs. +- Demo: Added a few more things under "Child windows" (changing ImGuiCol_ChildBg, positioning child, using IsItemHovered after a child). - Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file to ease integration. diff --git a/docs/TODO.txt b/docs/TODO.txt index bcd2fb11..4c2a2037 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -30,6 +30,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: GetWindowSize() returns (0,0) when not calculated? (#1045) - window: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. - window: investigate better auto-positioning for new windows. + - 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?). - scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet. - scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y). (2017-08-20: can't repro) - scrolling/style: shadows on scrollable areas to denote that there is more contents diff --git a/imgui.cpp b/imgui.cpp index c3d6373e..1ec4a27a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4152,6 +4152,10 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size child_window->ChildId = id; child_window->AutoFitChildAxises = auto_fit_axises; + // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. + // While this is not really documented/defined, it seems that the expected thing to do. + parent_window->DC.CursorPos = child_window->Pos; + // Process navigation-in immediately so NavInit can run on first frame if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d89bba1f..9e7b748b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1488,7 +1488,7 @@ static void ShowDemoWindowWidgets() ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); ImGui::BeginChild("child", ImVec2(0, 50), true); - ImGui::Text("This is another child window for testing with the _ChildWindows flag."); + ImGui::Text("This is another child window for testing the _ChildWindows flag."); ImGui::EndChild(); if (embed_all_inside_a_child_window) ImGui::EndChild(); @@ -1521,8 +1521,9 @@ static void ShowDemoWindowLayout() if (!ImGui::CollapsingHeader("Layout")) return; - if (ImGui::TreeNode("Child regions")) + if (ImGui::TreeNode("Child windows")) { + ShowHelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); static bool disable_mouse_wheel = false; static bool disable_menu = false; ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); @@ -1537,7 +1538,8 @@ static void ShowDemoWindowLayout() // Child 1: no border, enable horizontal scrollbar { - ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 300), false, ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0); + ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); for (int i = 0; i < 100; i++) { ImGui::Text("%04d: scrollable region", i); @@ -1553,8 +1555,9 @@ static void ShowDemoWindowLayout() // Child 2: rounded border { + ImGuiWindowFlags window_flags = (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); - ImGui::BeginChild("Child2", ImVec2(0, 300), true, (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar)); + ImGui::BeginChild("Child2", ImVec2(0, 260), true, window_flags); if (!disable_menu && ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Menu")) @@ -1576,6 +1579,27 @@ static void ShowDemoWindowLayout() ImGui::PopStyleVar(); } + ImGui::Separator(); + + // Demonstrate a few extra things + // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) + // - Using SetCursorPos() to position the child window (because the child window is an item from the POV of the parent window) + // You can also call SetNextWindowPos() to position the child window. The parent window will effectively layout from this position. + // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window) + // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this. + { + ImGui::SetCursorPosX(50); + ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); + ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None); + for (int n = 0; n < 50; n++) + ImGui::Text("Some test %d", n); + ImGui::EndChild(); + ImVec2 child_rect_min = ImGui::GetItemRectMin(); + ImVec2 child_rect_max = ImGui::GetItemRectMax(); + ImGui::PopStyleColor(); + ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); + } + ImGui::TreePop(); } @@ -1819,7 +1843,7 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Text Baseline Alignment")) { - ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)"); + ShowHelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets."); ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine(); @@ -1874,7 +1898,8 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Scrolling")) { - ImGui::TextWrapped("(Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position.)"); + ShowHelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position."); + static bool track = true; static int track_line = 50, scroll_to_px = 200; ImGui::Checkbox("Track", &track); @@ -1915,8 +1940,7 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Horizontal Scrolling")) { - ImGui::Bullet(); ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag."); - ImGui::Bullet(); ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); + ShowHelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); static int lines = 7; ImGui::SliderInt("Lines", &lines, 1, 15); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); From 8399fb507182bacf9c438e335305a12062fdaba2 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 19 Dec 2018 15:20:18 +0100 Subject: [PATCH 036/195] Changed ImGuiCol_ChildBg to (0,0,0,0) in Dark style instead of (1,1,1,0), to match other styles. Shouldn't have any effect for the end-user. --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ea89a5f6..7bd85ab3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -175,7 +175,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); - colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); From 5691385a33dc359acb2fa74267d96a6bac85c924 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 11:41:24 +0100 Subject: [PATCH 037/195] IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. (#2004 + for cimgui) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 1 + imgui.h | 11 +++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index edf16b60..350743cd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,6 +60,7 @@ Other Changes: This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. +- IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. - Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. - Demo: "Simple Layout" and "Style Editor" are now using tabs. diff --git a/imgui.cpp b/imgui.cpp index 1ec4a27a..2aa675b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1111,6 +1111,7 @@ ImGuiIO::ImGuiIO() // Platform Functions BackendPlatformName = BackendRendererName = NULL; + BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; ClipboardUserData = NULL; diff --git a/imgui.h b/imgui.h index 431646b8..dfe7cc75 100644 --- a/imgui.h +++ b/imgui.h @@ -1240,9 +1240,12 @@ struct ImGuiIO // (the imgui_impl_xxxx back-end files are setting those up for you) //------------------------------------------------------------------ - // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) - const char* BackendPlatformName; - const char* BackendRendererName; + // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. + const char* BackendPlatformName; // = NULL + const char* BackendRendererName; // = NULL + void* BackendPlatformUserData; // = NULL + void* BackendRendererUserData; // = NULL + void* BackendLanguageUserData; // = NULL // Optional: Access OS clipboard // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) @@ -1253,7 +1256,7 @@ struct ImGuiIO // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) // (default to use native imm32 api on Windows) void (*ImeSetInputScreenPosFn)(int x, int y); - void* ImeWindowHandle; // (Windows) Set this to your HWND to get automatic IME cursor positioning. + void* ImeWindowHandle; // (Windows) Set this to your HWND to get automatic IME cursor positioning. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! From 39dde66b21261328eac6d284e962d209a4c3b061 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 11:48:52 +0100 Subject: [PATCH 038/195] IO: Realigned all fields, very minor comments change. This is nearly a no-op if you don't ignore Spaces. --- imgui.h | 128 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/imgui.h b/imgui.h index dfe7cc75..98e34e19 100644 --- a/imgui.h +++ b/imgui.h @@ -1202,38 +1202,38 @@ struct ImGuiStyle struct ImGuiIO { //------------------------------------------------------------------ - // Configuration (fill once) // Default value: + // Configuration (fill once) // Default value //------------------------------------------------------------------ - ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. - ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. - ImVec2 DisplaySize; // // Main display size, in pixels. For clamping windows positions. - 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. - const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified). - float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. - float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. - float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. - int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. - float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). - float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. - void* UserData; // = NULL // Store your own data for retrieval by callbacks. - - ImFontAtlas* Fonts; // // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array. - float FontGlobalScale; // = 1.0f // Global scale all fonts - bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. - ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. - ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui. - ImVec2 DisplayVisibleMin; // (0.0f,0.0f) // [OBSOLETE] If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area. - ImVec2 DisplayVisibleMax; // (0.0f,0.0f) // [OBSOLETE: just use io.DisplaySize!] If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. + ImVec2 DisplaySize; // // Main display size, in pixels. For clamping windows positions. + 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. + const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. + float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + void* UserData; // = NULL // Store your own data for retrieval by callbacks. + + ImFontAtlas*Fonts; // // Load, rasterize and pack one or more fonts into a single texture. + float FontGlobalScale; // = 1.0f // Global scale all fonts + bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui. + ImVec2 DisplayVisibleMin; // // [OBSOLETE] If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area. + ImVec2 DisplayVisibleMax; // // [OBSOLETE] Just use io.DisplaySize! If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize // Miscellaneous configuration options - bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. - bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) - bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) - bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) - bool ConfigWindowsMoveFromTitleBarOnly;// = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) + bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly;// = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. //------------------------------------------------------------------ // Platform Functions @@ -1241,11 +1241,11 @@ struct ImGuiIO //------------------------------------------------------------------ // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. - const char* BackendPlatformName; // = NULL - const char* BackendRendererName; // = NULL - void* BackendPlatformUserData; // = NULL - void* BackendRendererUserData; // = NULL - void* BackendLanguageUserData; // = NULL + const char* BackendPlatformName; // = NULL + const char* BackendRendererName; // = NULL + void* BackendPlatformUserData; // = NULL + void* BackendRendererUserData; // = NULL + void* BackendLanguageUserData; // = NULL // Optional: Access OS clipboard // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) @@ -1256,7 +1256,7 @@ struct ImGuiIO // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) // (default to use native imm32 api on Windows) void (*ImeSetInputScreenPosFn)(int x, int y); - void* ImeWindowHandle; // (Windows) Set this to your HWND to get automatic IME cursor positioning. + void* ImeWindowHandle; // = NULL // (Windows) Set this to your HWND to get automatic IME cursor positioning. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! @@ -1284,46 +1284,46 @@ struct ImGuiIO float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame, all values will be cleared back to zero in ImGui::EndFrame) // Functions - IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[] - IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Add new characters into InputCharacters[] from an UTF-8 string - inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Clear the text input buffer manually + IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[] + IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Add new characters into InputCharacters[] from an UTF-8 string + inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Clear the text input buffer manually //------------------------------------------------------------------ // Output - Retrieve after calling NewFrame() //------------------------------------------------------------------ - bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). - bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). - bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). - bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. - bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself. - bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. - bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events). - float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames - int MetricsRenderVertices; // Vertices output during last call to Render() - int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 - int MetricsRenderWindows; // Number of visible windows - int MetricsActiveWindows; // Number of active windows - int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. - ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself. + bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. //------------------------------------------------------------------ // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ - ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) - ImVec2 MouseClickedPos[5]; // Position at time of clicking - double MouseClickedTime[5]; // Time of last click (used to figure out double-click) - bool MouseClicked[5]; // Mouse button went from !Down to Down - bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? - bool MouseReleased[5]; // Mouse button went from Down to !Down - bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds. - float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) - float MouseDownDurationPrev[5]; // Previous time the mouse button has been down - ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point - float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point - float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) - float KeysDownDurationPrev[512]; // Previous duration the key has been down + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds. + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point + float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) + float KeysDownDurationPrev[512]; // Previous duration the key has been down float NavInputsDownDuration[ImGuiNavInput_COUNT]; float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; From a0e5bb95329e33519f0f3c993326d3a3df38aef1 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 12:15:15 +0100 Subject: [PATCH 039/195] Viewport: Corrected/clarified comments. Moved RenderPlatformWindowsDefault() next to UpdatePlatformWindow(). Removed unnecessary flag check. --- imgui.cpp | 101 +++++++++++++++++++++++++++--------------------------- imgui.h | 15 ++++---- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fc2db679..e0cce5b0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7630,7 +7630,8 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) window->ViewportId = window->Viewport->ID; } -// Called by imgui at the end of the main loop, after EndFrame() +// Called by user at the end of the main loop, after EndFrame() +// This will handle the creation/update of all OS windows via function defined in the ImGuiPlatformIO api. void ImGui::UpdatePlatformWindows() { ImGuiContext& g = *GImGui; @@ -7658,34 +7659,34 @@ void ImGui::UpdatePlatformWindows() if (viewport->LastFrameActive < g.FrameCount) continue; - // New windows that appears directly in a new viewport won't always have a size on their frame + // New windows that appears directly in a new viewport won't always have a size on their first frame if (viewport->Size.x <= 0 || viewport->Size.y <= 0) continue; // Update common viewport flags for owned viewports - if (viewport->Window != NULL) + if (ImGuiWindow* window = viewport->Window) { ImGuiViewportFlags flags = viewport->Flags & ~(ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration); - if (viewport->Window->Flags & ImGuiWindowFlags_Tooltip) + if (window->Flags & ImGuiWindowFlags_Tooltip) flags |= ImGuiViewportFlags_TopMost; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) != 0 || (viewport->Window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) + if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) != 0 || (window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) flags |= ImGuiViewportFlags_NoTaskBarIcon; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (viewport->Window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) + if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) flags |= ImGuiViewportFlags_NoDecoration; viewport->Flags = flags; } // Create window - bool is_new_window = (viewport->PlatformWindowCreated == false); - if (is_new_window) + bool is_new_platform_window = (viewport->PlatformWindowCreated == false); + if (is_new_platform_window) { //IMGUI_DEBUG_LOG("Create Platform Window %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a"); g.PlatformIO.Platform_CreateWindow(viewport); if (g.PlatformIO.Renderer_CreateWindow != NULL) g.PlatformIO.Renderer_CreateWindow(viewport); viewport->LastNameHash = 0; - viewport->LastPlatformPos = viewport->LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX); // By clearing those we'll enforce a call to Platform_SetWindowPos/Platform_SetWindowSize before Platform_ShowWindow - viewport->LastRendererSize = viewport->Size; + viewport->LastPlatformPos = viewport->LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX); // By clearing those we'll enforce a call to Platform_SetWindowPos/Size below, before Platform_ShowWindow (FIXME: Is that necessary?) + viewport->LastRendererSize = viewport->Size; // We don't need to call Renderer_SetWindowSize() as it is expected Renderer_CreateWindow() already did it. viewport->PlatformWindowCreated = true; } @@ -7708,29 +7709,32 @@ void ImGui::UpdatePlatformWindows() if (viewport->LastNameHash != title_hash) { char title_end_backup_c = *title_end; - *title_end = 0; // Cut existing buffer short instead of doing an alloc/free + *title_end = 0; // Cut existing buffer short instead of doing an alloc/free, no small gain. g.PlatformIO.Platform_SetWindowTitle(viewport, title_begin); *title_end = title_end_backup_c; viewport->LastNameHash = title_hash; } } - // Update alpha + // Update alpha (if it changed) if (viewport->LastAlpha != viewport->Alpha && g.PlatformIO.Platform_SetWindowAlpha) g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport->Alpha); viewport->LastAlpha = viewport->Alpha; - // Show window. On startup ensure platform window don't get focus - if (is_new_window) + if (is_new_platform_window) { - if (g.FrameCount < 3) // Give a few frames for the application to stabilize (nested contents may lead to viewport being created a few frames late) + // On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late) + if (g.FrameCount < 3) viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing; + + // Show window g.PlatformIO.Platform_ShowWindow(viewport); - } - // Even without focus, we assume the window becomes front-most. This is used by our platform z-order heuristic when io.MouseHoveredViewport is not available. - if (is_new_window && viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount) - viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount; + // Even without focus, we assume the window becomes front-most. + // This is useful for our platform z-order heuristic when io.MouseHoveredViewport is not available. + if (viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount) + viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount; + } // Clear request flags viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false; @@ -7757,6 +7761,34 @@ void ImGui::UpdatePlatformWindows() } } +// This is a default/basic function for performing the rendering/swap of multiple Platform Windows. +// Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves. +// The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself: +// +// ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); +// for (int i = 1; i < platform_io.Viewports.Size; i++) +// MyRenderFunction(platform_io.Viewports[i], my_args); +// for (int i = 1; i < platform_io.Viewports.Size; i++) +// MySwapBufferFunction(platform_io.Viewports[i], my_args); +// +void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* renderer_render_arg) +{ + // Skip the main viewport (index 0), which is always fully handled by the application! + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + for (int i = 1; i < platform_io.Viewports.Size; i++) + { + ImGuiViewport* viewport = platform_io.Viewports[i]; + if (platform_io.Platform_RenderWindow) platform_io.Platform_RenderWindow(viewport, platform_render_arg); + if (platform_io.Renderer_RenderWindow) platform_io.Renderer_RenderWindow(viewport, renderer_render_arg); + } + for (int i = 1; i < platform_io.Viewports.Size; i++) + { + ImGuiViewport* viewport = platform_io.Viewports[i]; + if (platform_io.Platform_SwapBuffers) platform_io.Platform_SwapBuffers(viewport, platform_render_arg); + if (platform_io.Renderer_SwapBuffers) platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg); + } +} + static int ImGui::FindPlatformMonitorForPos(const ImVec2& pos) { ImGuiContext& g = *GImGui; @@ -7798,37 +7830,6 @@ static int ImGui::FindPlatformMonitorForRect(const ImRect& rect) return best_monitor_n; } -// This is a default/basic function for performing the rendering/swap of multiple platform windows. -// Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves. -// The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself: -// -// ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); -// for (int i = 1; i < platform_io.Viewports.Size; i++) -// MyRenderFunction(platform_io.Viewports[i], my_args); -// for (int i = 1; i < platform_io.Viewports.Size; i++) -// MySwapBufferFunction(platform_io.Viewports[i], my_args); -// -void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* renderer_render_arg) -{ - if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) - return; - - // Skip the main viewport (index 0), which is always fully handled by the application! - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - for (int i = 1; i < platform_io.Viewports.Size; i++) - { - ImGuiViewport* viewport = platform_io.Viewports[i]; - if (platform_io.Platform_RenderWindow) platform_io.Platform_RenderWindow(viewport, platform_render_arg); - if (platform_io.Renderer_RenderWindow) platform_io.Renderer_RenderWindow(viewport, renderer_render_arg); - } - for (int i = 1; i < platform_io.Viewports.Size; i++) - { - ImGuiViewport* viewport = platform_io.Viewports[i]; - if (platform_io.Platform_SwapBuffers) platform_io.Platform_SwapBuffers(viewport, platform_render_arg); - if (platform_io.Renderer_SwapBuffers) platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg); - } -} - void ImGui::DestroyPlatformWindow(ImGuiViewportP* viewport) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 3601dada..65d481e7 100644 --- a/imgui.h +++ b/imgui.h @@ -2143,13 +2143,13 @@ struct ImGuiPlatformMonitor }; // (Optional) Setup required only if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) is enabled. -// Access via ImGui::GetPlatformIO(). This is designed so we can mix and match two imgui_impl_xxxx files, one for -// the Platform (~window handling), one for Renderer. Custom engine back-ends will often provide both Platform -// and Renderer interfaces and thus may not need to use all functions. +// Access via ImGui::GetPlatformIO(). This is designed so we can mix and match two imgui_impl_xxxx files, +// one for the Platform (~window handling), one for Renderer. Custom engine back-ends will often provide +// both Platform and Renderer interfaces and so may not need to use all functions. // Platform functions are typically called before their Renderer counterpart, // apart from Destroy which are called the other way. // RenderPlatformWindowsDefault() is that helper that iterate secondary viewports and call, in this order: -// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers() +// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers() // You may skip using RenderPlatformWindowsDefault() and call your draw/swap functions yourself if you need // specific behavior for your multi-window rendering. struct ImGuiPlatformIO @@ -2159,6 +2159,7 @@ struct ImGuiPlatformIO //------------------------------------------------------------------ // (Optional) Platform functions (e.g. Win32, GLFW, SDL2) + // Most of them are called by ImGui::UpdatePlatformWindows() and ImGui::RenderPlatformWindowsDefault(). void (*Platform_CreateWindow)(ImGuiViewport* vp); // Create a new platform window for the given viewport void (*Platform_DestroyWindow)(ImGuiViewport* vp); void (*Platform_ShowWindow)(ImGuiViewport* vp); // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them first @@ -2171,7 +2172,7 @@ struct ImGuiPlatformIO bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp); void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* title); void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // (Optional) Setup window transparency - void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render (platform side) + void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (platform side) float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Called during Begin() every time the viewport we are outputting into changes, so back-end has a chance to swap fonts to adjust style. @@ -2213,8 +2214,8 @@ enum ImGuiViewportFlags_ // The viewports created and managed by imgui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport. struct ImGuiViewport { - ImGuiID ID; - ImGuiViewportFlags Flags; + ImGuiID ID; // Unique identifier for the viewport + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ ImVec2 Pos; // Position of viewport both in imgui space and in OS desktop/native space ImVec2 Size; // Size of viewport in pixel float DpiScale; // 1.0f = 96 DPI = No extra scale From 8fc19d21941789a7a3ca7d32ab0c36ef6b696042 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 16:56:29 +0100 Subject: [PATCH 040/195] Removed IMGUI_HAS_TABS from Docking branch, it's not defined anywhere anymore. --- imgui.h | 1 - 1 file changed, 1 deletion(-) diff --git a/imgui.h b/imgui.h index 52565492..c379203a 100644 --- a/imgui.h +++ b/imgui.h @@ -50,7 +50,6 @@ Index of this file: #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) #define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch #define IMGUI_HAS_DOCK 1 // Docking WIP branch -#define IMGUI_HAS_TABS 1 // Docking WIP branch // Define attributes of all API symbols declarations (e.g. for DLL under Windows) // IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h) From 5794c0491ad8f11beaea512e25d40714cec760f4 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 19:19:33 +0100 Subject: [PATCH 041/195] Docking: Fix an edge case failing to dock into an explicit dockspace which only have inactive nodes (because all the windows are inactive). (#2246, #2109) --- imgui.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 476c1d25..503ea65f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9916,6 +9916,7 @@ namespace ImGui static void DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size); static void DockNodeTreeUpdateSplitter(ImGuiDockNode* node); static ImGuiDockNode* DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos); + static ImGuiDockNode* DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node); // Settings static void DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id); @@ -11399,11 +11400,20 @@ static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo ImGuiContext& g = *GImGui; IM_ASSERT(g.CurrentWindow == host_window); // Because we rely on font size to calculate tab sizes + // There is an edge case when docking into a dockspace which only has inactive nodes. + // In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive. + // Because the inactive leaf node doesn't have proper pos/size yet, we'll use the root node as reference. + ImGuiDockNode* ref_node_for_rect = (host_node && !host_node->IsVisible) ? DockNodeGetRootNode(host_node) : host_node; + if (ref_node_for_rect) + IM_ASSERT(ref_node_for_rect->IsVisible); + + // Build a tentative future node (reuse same structure because it is practical) data->FutureNode.HasCloseButton = (host_node ? host_node->HasCloseButton : host_window->HasCloseButton) || (root_payload->HasCloseButton); data->FutureNode.HasCollapseButton = host_node ? true : ((host_window->Flags & ImGuiWindowFlags_NoCollapse) == 0); - data->FutureNode.Pos = host_node ? host_node->Pos : host_window->Pos; - data->FutureNode.Size = host_node ? host_node->Size : host_window->Size; + data->FutureNode.Pos = host_node ? ref_node_for_rect->Pos : host_window->Pos; + data->FutureNode.Size = host_node ? ref_node_for_rect->Size : host_window->Size; + // Figure out here we are allowed to dock const bool src_is_visibly_splitted = root_payload->DockNodeAsHost && root_payload->DockNodeAsHost->IsSplitNode() && (root_payload->DockNodeAsHost->OnlyNodeWithWindows == NULL); data->IsCenterAvailable = !is_outer_docking; if (src_is_visibly_splitted && (!host_node || !host_node->IsEmpty())) @@ -11837,6 +11847,17 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node) DockNodeTreeUpdateSplitter(child_1); } +ImGuiDockNode* ImGui::DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node) +{ + if (node->IsLeafNode()) + return node; + if (ImGuiDockNode* leaf_node = DockNodeTreeFindFallbackLeafNode(node->ChildNodes[0])) + return leaf_node; + if (ImGuiDockNode* leaf_node = DockNodeTreeFindFallbackLeafNode(node->ChildNodes[1])) + return leaf_node; + return NULL; +} + ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos) { if (!node->IsVisible) @@ -11856,6 +11877,16 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos) return hovered_node; if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos)) return hovered_node; + + // There is an edge case when docking into a dockspace which only has inactive nodes (because none of the windows are active) + // In this case we need to fallback into any leaf mode, possibly the central node. + if (node->IsDockSpace && node->IsRootNode()) + { + if (node->CentralNode && node->IsLeafNode()) // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first. + return node->CentralNode; + return DockNodeTreeFindFallbackLeafNode(node); + } + return NULL; } From b471813f54092f59ec64d902bc2254c6675baddf Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 20:01:02 +0100 Subject: [PATCH 042/195] Made it illegal to call Begin("") with an empty string. This somehow accidentally worked before but had various undesirable side-effect as the window would have ID zero. In particular it is causing problems in viewport/docking branches. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 350743cd..e2ac095f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,6 +37,8 @@ Breaking Changes: - Renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges and removed its [Beta] mark. The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. +- Made it illegal to call Begin("") with an empty string. This somehow accidentally worked before but had various + undesirable side-effect as the window would have ID zero. In particular it is causing problems in viewport/docking branches. Other Changes: - Added BETA api for Tab Bar/Tabs widgets: (#261, #351) diff --git a/imgui.cpp b/imgui.cpp index 2aa675b4..38a393e4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4621,7 +4621,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - IM_ASSERT(name != NULL); // Window name required + IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame() IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet From 8dd83c5fe8e8c16480509ebf0c58f76517e099e4 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 22:28:31 +0100 Subject: [PATCH 043/195] Examples: SDL: SDL_GetMouseState() seems problematic, movements feels laggy in the non-viewport code path. (#1542, #2117) --- examples/imgui_impl_sdl.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 3e883550..5ac68241 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -253,39 +253,39 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons() io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); #endif - int mx, my; - Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); + int mouse_x, mouse_y; + Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x, &mouse_y); // NB: We don't use the x/y results from SDL_GetMouseState() + SDL_GetGlobalMouseState(&mouse_x, &mouse_y); io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; #if SDL_HAS_CAPTURE_MOUSE && !defined(__EMSCRIPTEN__) - SDL_Window* focused_window = SDL_GetKeyboardFocus(); - if (focused_window) + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) - SDL_GetGlobalMouseState(&mx, &my); + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) + if (SDL_Window* focused_window = SDL_GetKeyboardFocus()) if (ImGui::FindViewportByPlatformHandle((void*)focused_window) != NULL) - io.MousePos = ImVec2((float)mx, (float)my); - } - else + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + } + else +#endif + { + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) + if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) { - // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) - if (focused_window == g_Window) - io.MousePos = ImVec2((float)mx, (float)my); + int window_x, window_y; + SDL_GetWindowPosition(g_Window, &window_x, &window_y); + io.MousePos = ImVec2((float)(mouse_x - window_x), (float)(mouse_y - window_y)); } } // We already retrieve global mouse position, SDL_CaptureMouse() also let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't trigger the OS window resize cursor // The function is only supported from SDL 2.0.4 (released Jan 2016) +#if SDL_HAS_CAPTURE_MOUSE bool any_mouse_button_down = ImGui::IsAnyMouseDown(); SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); -#else - if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) - io.MousePos = ImVec2((float)mx, (float)my); #endif } From d9fda227637065f07f419ab5ec0669dfbd016e76 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 22:33:51 +0100 Subject: [PATCH 044/195] Viewport: Fixed not clearing request flags in main viewport, which led some back-end (SDL) to break on resize as PlatformRequestResize would stay true forever and inhibit new sizes passed to AddUpdateViewport(). (#1542) --- imgui.cpp | 5 +++-- imgui_internal.h | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6eeea325..a69763fa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3818,6 +3818,7 @@ void ImGui::EndFrame() IM_ASSERT(viewport->Window != NULL); g.PlatformIO.Viewports.push_back(viewport); } + g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called // Sort the window list so that all child windows are after their parent // We cannot do that on FocusWindow() because childs may not exist yet @@ -7760,7 +7761,7 @@ void ImGui::UpdatePlatformWindows() } // Clear request flags - viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false; + viewport->ClearRequestFlags(); } // Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport. @@ -7865,7 +7866,7 @@ void ImGui::DestroyPlatformWindow(ImGuiViewportP* viewport) viewport->PlatformHandle = NULL; viewport->RendererUserData = viewport->PlatformHandle = NULL; viewport->PlatformWindowCreated = false; - viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false; + viewport->ClearRequestFlags(); } void ImGui::DestroyPlatformWindows() diff --git a/imgui_internal.h b/imgui_internal.h index dc0e7815..56f4f352 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -672,10 +672,11 @@ struct ImGuiViewportP : public ImGuiViewport ImVec2 LastPlatformSize; ImVec2 LastRendererSize; - ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = PlatformWindowMinimized = false; Window = NULL; OverlayDrawList = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } - ~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); } - ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - ImVec2 GetCenter() const{ return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } + ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = PlatformWindowMinimized = false; Window = NULL; OverlayDrawList = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } + ~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); } + ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } + void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } }; struct ImGuiNavMoveResult From 62cfdceac15b57f834d836ef944e66b70a4405e6 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 22:40:22 +0100 Subject: [PATCH 045/195] Examples: Viewport: Moved the "make current GL context" to reduce the amount of call and hopefully be more explicit about viewport enabled vs disabled requirements. (#1542) --- examples/example_glfw_opengl2/main.cpp | 2 +- examples/example_glfw_opengl3/main.cpp | 3 +-- examples/example_sdl_opengl2/main.cpp | 3 ++- examples/example_sdl_opengl3/main.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index d5a5fd25..f87a989a 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -140,9 +140,9 @@ int main(int, char**) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); + glfwMakeContextCurrent(window); } - glfwMakeContextCurrent(window); glfwSwapBuffers(window); } diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 93dcead5..ffd23cc0 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -178,7 +178,6 @@ int main(int, char**) // Rendering ImGui::Render(); int display_w, display_h; - glfwMakeContextCurrent(window); glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); @@ -190,9 +189,9 @@ int main(int, char**) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); + glfwMakeContextCurrent(window); } - glfwMakeContextCurrent(window); glfwSwapBuffers(window); } diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index 3366d413..346dee2f 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -32,6 +32,7 @@ int main(int, char**) SDL_GetCurrentDisplayMode(0, ¤t); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); SDL_GLContext gl_context = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync // Setup Dear ImGui context @@ -142,9 +143,9 @@ int main(int, char**) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); + SDL_GL_MakeCurrent(window, gl_context); } - SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SwapWindow(window); } diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index 93a49a10..1d5de155 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -56,6 +56,7 @@ int main(int, char**) SDL_GetCurrentDisplayMode(0, ¤t); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE); SDL_GLContext gl_context = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync // Initialize OpenGL loader @@ -177,7 +178,6 @@ int main(int, char**) // Rendering ImGui::Render(); - SDL_GL_MakeCurrent(window, gl_context); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); @@ -188,9 +188,9 @@ int main(int, char**) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); + SDL_GL_MakeCurrent(window, gl_context); } - SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SwapWindow(window); } From d5b22fb6350e2078318f82fe3174c777e066cd64 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 20 Dec 2018 22:58:34 +0100 Subject: [PATCH 046/195] Examples: Setting up style before bindings, so in complex binding (vulkan/dx12) it isn't miles away from the context creation. --- examples/example_allegro5/main.cpp | 8 ++++---- examples/example_apple_metal/Shared/Renderer.mm | 6 ++---- examples/example_apple_opengl2/main.mm | 8 ++++---- examples/example_freeglut_opengl2/main.cpp | 8 ++++---- examples/example_glfw_opengl2/main.cpp | 8 ++++---- examples/example_glfw_opengl3/main.cpp | 8 ++++---- examples/example_glfw_vulkan/main.cpp | 8 ++++---- examples/example_marmalade/main.cpp | 8 ++++---- examples/example_sdl_opengl2/main.cpp | 8 ++++---- examples/example_sdl_opengl3/main.cpp | 8 ++++---- examples/example_sdl_vulkan/main.cpp | 8 ++++---- examples/example_win32_directx10/main.cpp | 8 ++++---- examples/example_win32_directx11/main.cpp | 8 ++++---- examples/example_win32_directx12/main.cpp | 8 ++++---- examples/example_win32_directx9/main.cpp | 8 ++++---- 15 files changed, 58 insertions(+), 60 deletions(-) diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp index a1fdd825..ddbdf76d 100644 --- a/examples/example_allegro5/main.cpp +++ b/examples/example_allegro5/main.cpp @@ -28,13 +28,13 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - // Setup Platform/Renderer bindings - ImGui_ImplAllegro5_Init(display); - - // Setup Style + // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings + ImGui_ImplAllegro5_Init(display); + // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_apple_metal/Shared/Renderer.mm b/examples/example_apple_metal/Shared/Renderer.mm index 95218eae..30ccf5a1 100644 --- a/examples/example_apple_metal/Shared/Renderer.mm +++ b/examples/example_apple_metal/Shared/Renderer.mm @@ -26,11 +26,9 @@ IMGUI_CHECKVERSION(); ImGui::CreateContext(); - (void)ImGui::GetIO(); - - ImGui_ImplMetal_Init(_device); - ImGui::StyleColorsDark(); + + ImGui_ImplMetal_Init(_device); } return self; diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index 1b79ca64..ff179d82 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -243,14 +243,14 @@ ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplOSX_Init(); ImGui_ImplOpenGL2_Init(); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_freeglut_opengl2/main.cpp b/examples/example_freeglut_opengl2/main.cpp index 6ebf324d..952f3f44 100644 --- a/examples/example_freeglut_opengl2/main.cpp +++ b/examples/example_freeglut_opengl2/main.cpp @@ -100,15 +100,15 @@ int main(int argc, char** argv) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplFreeGLUT_Init(); ImGui_ImplFreeGLUT_InstallFuncs(); ImGui_ImplOpenGL2_Init(); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index 7074b5d7..db16a883 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -43,14 +43,14 @@ int main(int, char**) //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL2_Init(); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index cf939c11..dee0dd9d 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -89,14 +89,14 @@ int main(int, char**) //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 18016003..d6d161b8 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -357,6 +357,10 @@ int main(int, char**) //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplGlfw_InitForVulkan(window, true); ImGui_ImplVulkan_InitInfo init_info = {}; @@ -371,10 +375,6 @@ int main(int, char**) init_info.CheckVkResultFn = check_vk_result; ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_marmalade/main.cpp b/examples/example_marmalade/main.cpp index c29164cd..f2249acf 100644 --- a/examples/example_marmalade/main.cpp +++ b/examples/example_marmalade/main.cpp @@ -22,13 +22,13 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - // Setup Platform/Renderer bindings - ImGui_Marmalade_Init(true); - - // Setup Style + // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings + ImGui_Marmalade_Init(true); + // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index 54351f13..af0d297e 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -40,14 +40,14 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL2_Init(); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index dc31a6e3..c28d52cc 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -80,14 +80,14 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index f7dedc8d..03993eb4 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -338,6 +338,10 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplSDL2_InitForVulkan(window); ImGui_ImplVulkan_InitInfo init_info = {}; @@ -352,10 +356,6 @@ int main(int, char**) init_info.CheckVkResultFn = check_vk_result; ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 4ea355b8..d6229335 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -116,14 +116,14 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX10_Init(g_pd3dDevice); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index e58a338c..eb06ac59 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -119,14 +119,14 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 3379b2fe..285fd821 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -292,6 +292,10 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, @@ -299,10 +303,6 @@ int main(int, char**) g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index 27944e00..a7d5173c 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -81,14 +81,14 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsClassic(); + // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX9_Init(g_pd3dDevice); - // Setup Style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsClassic(); - // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. From afe9c5c5f749f981007b140fe612763c5eff2441 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 16:26:17 +0100 Subject: [PATCH 047/195] Examples: SDL: Fixed compilation for SDL 2..0.3 and less (running on our test servers) and clarified a bit of the messy situation. Followup to 8dd83c5. (#1542, #2117) --- examples/imgui_impl_sdl.cpp | 73 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 5ac68241..f2e28f56 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -42,11 +42,10 @@ #include "imgui_impl_sdl.h" // SDL -// (the multi-viewports feature requires SDL features supported from SDL 2.0.5+) +// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended) #include #include -#define SDL_HAS_WARP_MOUSE_GLOBAL SDL_VERSION_ATLEAST(2,0,4) -#define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4) +#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5) #define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5) #define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5) @@ -149,10 +148,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context) // Setup back-end capabilities flags ImGuiIO& io = ImGui::GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) -#if SDL_HAS_WARP_MOUSE_GLOBAL - io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) -#endif -#if SDL_HAS_CAPTURE_MOUSE +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) #endif io.BackendPlatformName = "imgui_impl_sdl"; @@ -213,9 +209,9 @@ bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context) bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window) { - #if !SDL_HAS_VULKAN +#if !SDL_HAS_VULKAN IM_ASSERT(0 && "Unsupported"); - #endif +#endif return ImGui_ImplSDL2_Init(window, NULL); } @@ -235,57 +231,72 @@ void ImGui_ImplSDL2_Shutdown() memset(g_MouseCursors, 0, sizeof(g_MouseCursors)); } +// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4. static void ImGui_ImplSDL2_UpdateMousePosAndButtons() { ImGuiIO& io = ImGui::GetIO(); io.MouseHoveredViewport = 0; - // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - // (When multi-viewports are enabled, all imgui positions are same as OS positions.) -#if SDL_HAS_WARP_MOUSE_GLOBAL - if (!io.WantSetMousePos) - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); - else if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0) - SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y); - else - SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y); -#else - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + // [1] + // Only when requested by io.WantSetMousePos: set OS mouse pos from Dear ImGui mouse pos. + // (rarely used, mostly when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + { +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y); + else #endif - - int mouse_x, mouse_y; - Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x, &mouse_y); // NB: We don't use the x/y results from SDL_GetMouseState() - SDL_GetGlobalMouseState(&mouse_x, &mouse_y); - io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y); + } + else + { + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + } + + // [2] + // Set Dear ImGui mouse pos from OS mouse pos + get buttons. (this is the common behavior) + int mouse_x_local, mouse_y_local; + Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local); + io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; -#if SDL_HAS_CAPTURE_MOUSE && !defined(__EMSCRIPTEN__) +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + + // SDL 2.0.4 and later has SDL_GetGlobalMouseState() and SDL_CaptureMouse() + int mouse_x_global, mouse_y_global; + SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global); + +#if !defined(__EMSCRIPTEN__) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) if (SDL_Window* focused_window = SDL_GetKeyboardFocus()) if (ImGui::FindViewportByPlatformHandle((void*)focused_window) != NULL) - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + io.MousePos = ImVec2((float)mouse_x_global, (float)mouse_y_global); } else #endif { - // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) + // Single-viewport mode: mouse position in client window coordinatesio.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) { int window_x, window_y; SDL_GetWindowPosition(g_Window, &window_x, &window_y); - io.MousePos = ImVec2((float)(mouse_x - window_x), (float)(mouse_y - window_y)); + io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y)); } } - // We already retrieve global mouse position, SDL_CaptureMouse() also let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't trigger the OS window resize cursor + // SDL_CaptureMouse() will let the OS know that our drag outside the SDL window boundaries shouldn't trigger the OS window resize cursor. // The function is only supported from SDL 2.0.4 (released Jan 2016) -#if SDL_HAS_CAPTURE_MOUSE bool any_mouse_button_down = ImGui::IsAnyMouseDown(); SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); +#else + // SDL 2.0.3 and before: single-viewport only + if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) + io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local); #endif } From b1cd52b67439a696b29e694f45cb317a7b3dfc19 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 16:33:50 +0100 Subject: [PATCH 048/195] Examples: SDL: Avoid testing for SDL_GetKeyboardFocus() on Android and iOS (like Emscripten). (#421) --- examples/imgui_impl_sdl.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 873c50f8..28253db0 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'. // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. @@ -42,8 +43,11 @@ // (the multi-viewports feature requires SDL features supported from SDL 2.0.5+) #include #include +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif -#define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4) +#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) #define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5) #if !SDL_HAS_VULKAN @@ -182,9 +186,9 @@ bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context) bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window) { - #if !SDL_HAS_VULKAN +#if !SDL_HAS_VULKAN IM_ASSERT(0 && "Unsupported"); - #endif +#endif return ImGui_ImplSDL2_Init(window); } @@ -220,7 +224,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons() io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; -#if SDL_HAS_CAPTURE_MOUSE && !defined(__EMSCRIPTEN__) +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)) SDL_Window* focused_window = SDL_GetKeyboardFocus(); if (g_Window == focused_window) { From 2889a14f86823c4b39b6e4d070fef19064167ab2 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 16:45:24 +0100 Subject: [PATCH 049/195] Build fix for master. --- examples/imgui_impl_sdl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 28253db0..730bce80 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -224,7 +224,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons() io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)) +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) SDL_Window* focused_window = SDL_GetKeyboardFocus(); if (g_Window == focused_window) { From 238321c15920ee58b2886e7917179e4e9fb51e18 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 16:53:56 +0100 Subject: [PATCH 050/195] Fix merge in Docking branch, remove ConfigDockingWithShift flag from DX11 example + misnamed function. --- examples/example_win32_directx11/main.cpp | 1 - examples/example_win32_directx9/main.cpp | 3 --- imgui.cpp | 6 +++--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index da6100bd..bcedfd5b 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -139,7 +139,6 @@ int main(int, char**) //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge; io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: THIS CURRENTLY DOESN'T WORK AS EXPECTED. DON'T USE IN USER APP! io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // FIXME-DPI - io.ConfigDockingWithShift = true; // Setup Dear ImGui style ImGui::StyleColorsDark(); diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index a6560e69..565a844c 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -80,17 +80,14 @@ int main(int, char**) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls -<<<<<<< HEAD io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons; //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge; -======= // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); ->>>>>>> viewport // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); diff --git a/imgui.cpp b/imgui.cpp index dc3a099f..4f2ff59d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3734,11 +3734,11 @@ void ImGui::PopClipRect() window->ClipRect = window->DrawList->_ClipRectStack.back(); } -static ImGuiWindow* FindFromMostVisibleChildWindow(ImGuiWindow* window) +static ImGuiWindow* FindFrontMostVisibleChildWindow(ImGuiWindow* window) { for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--) if (IsWindowActiveAndVisible(window->DC.ChildWindows[n])) - return FindFromMostVisibleChildWindow(window->DC.ChildWindows[n]); + return FindFrontMostVisibleChildWindow(window->DC.ChildWindows[n]); return window; } @@ -3792,7 +3792,7 @@ void ImGui::EndFrame() { // Choose a draw list that will be front-most across all our children ImGuiWindow* window = g.NavWindowingTargetAnim; - ImDrawList* draw_list = FindFromMostVisibleChildWindow(window->RootWindow)->DrawList; + ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindow)->DrawList; draw_list->PushClipRectFullScreen(); // Docking: draw modal whitening background on other nodes of a same dock tree From a71d3c8cb367469eaaffb8855ce5979f45df4fde Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 18:40:16 +0100 Subject: [PATCH 051/195] Viewport: Misc comments following user feedbacks.. --- examples/example_glfw_opengl2/main.cpp | 5 ++++- examples/example_glfw_opengl3/main.cpp | 5 ++++- examples/example_sdl_opengl2/main.cpp | 6 +++++- examples/example_sdl_opengl3/main.cpp | 6 +++++- imgui.cpp | 8 ++++---- imgui_internal.h | 1 + 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index 5b0c9023..a3ffcb30 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -144,11 +144,14 @@ int main(int, char**) ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); // Update and Render additional Platform Windows + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. + // For this specific demo app we could also call glfwMakeContextCurrent(window) directly) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + GLFWwindow* backup_current_context = glfwGetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); - glfwMakeContextCurrent(window); + glfwMakeContextCurrent(backup_current_context); } glfwSwapBuffers(window); diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 4268a210..f5dd65f0 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -189,11 +189,14 @@ int main(int, char**) ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); // Update and Render additional Platform Windows + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. + // For this specific demo app we could also call glfwMakeContextCurrent(window) directly) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + GLFWwindow* backup_current_context = glfwGetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); - glfwMakeContextCurrent(window); + glfwMakeContextCurrent(backup_current_context); } glfwSwapBuffers(window); diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index d27606b7..47a5f4d2 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -147,11 +147,15 @@ int main(int, char**) ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); // Update and Render additional Platform Windows + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. + // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); - SDL_GL_MakeCurrent(window, gl_context); + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); } SDL_GL_SwapWindow(window); diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index f3aae2ff..fc777e30 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -188,11 +188,15 @@ int main(int, char**) ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); // Update and Render additional Platform Windows + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. + // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); - SDL_GL_MakeCurrent(window, gl_context); + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); } SDL_GL_SwapWindow(window); diff --git a/imgui.cpp b/imgui.cpp index a9b1fd70..3b78289a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3812,10 +3812,12 @@ void ImGui::EndFrame() viewport->LastPos = viewport->Pos; if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) continue; - if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)) + if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)) // Will be destroyed in UpdatePlatformWindows() continue; if (i > 0) IM_ASSERT(viewport->Window != NULL); + + // Add to user-facing list g.PlatformIO.Viewports.push_back(viewport); } g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called @@ -7680,11 +7682,9 @@ void ImGui::UpdatePlatformWindows() DestroyPlatformWindow(viewport); continue; } - if (viewport->LastFrameActive < g.FrameCount) - continue; // New windows that appears directly in a new viewport won't always have a size on their first frame - if (viewport->Size.x <= 0 || viewport->Size.y <= 0) + if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0 || viewport->Size.y <= 0) continue; // Update common viewport flags for owned viewports diff --git a/imgui_internal.h b/imgui_internal.h index 56f4f352..151b7a4b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -651,6 +651,7 @@ enum ImGuiViewportFlagsPrivate_ }; // ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!) +// Note that every instance of ImGuiViewport is in fact a ImGuiViewportP. struct ImGuiViewportP : public ImGuiViewport { int Idx; From a9a60a24c159e15935453078be9e59d19118ca32 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 23 Dec 2018 17:39:04 +0100 Subject: [PATCH 052/195] Tweaked asserts --- examples/imgui_impl_glfw.cpp | 4 ++-- examples/imgui_impl_sdl.cpp | 2 +- examples/imgui_impl_win32.cpp | 1 + imgui.cpp | 17 +++++++++++++---- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 2122c601..6c6f452d 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -267,9 +267,9 @@ static void ImGui_ImplGlfw_UpdateMouseCursor() void ImGui_ImplGlfw_NewFrame() { ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame() + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); - // Setup display size + // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; glfwGetWindowSize(g_Window, &w, &h); diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 730bce80..fbd420a6 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -271,7 +271,7 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() void ImGui_ImplSDL2_NewFrame(SDL_Window* window) { ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame() + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); // Setup display size (every frame to accommodate for window resizing) int w, h; diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 9bf8a81d..402025b3 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -142,6 +142,7 @@ static void ImGui_ImplWin32_UpdateMousePos() void ImGui_ImplWin32_NewFrame() { ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); // Setup display size (every frame to accommodate for window resizing) RECT rect; diff --git a/imgui.cpp b/imgui.cpp index 38a393e4..1629ebac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3553,7 +3553,7 @@ void ImGui::EndFrame() IM_ASSERT(g.Initialized); if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times. return; - IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()"); + IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) @@ -3562,8 +3562,17 @@ void ImGui::EndFrame() g.PlatformImeLastPos = g.PlatformImePos; } - // Hide implicit "Debug" window if it hasn't been used - IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls, did you forget to call end on g.CurrentWindow->Name? + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + else + IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + + // Hide implicit/fallback "Debug" window if it hasn't been used if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) g.CurrentWindow->Active = false; End(); @@ -3699,7 +3708,7 @@ void ImGui::Render() g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount; g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount; - // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData() + // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL) g.IO.RenderDrawListsFn(&g.DrawData); From d8451352737c08a5ee22b0d805415cb4a8327e5b Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 23 Dec 2018 17:54:20 +0100 Subject: [PATCH 053/195] Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function itself at the call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. Missing calls to End(), pass the assert, should not lead to crashes any more, nor to the fallback/debug window appearing on screen. (#1651). --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e2ac095f..5d7bad6a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,10 @@ Other Changes: This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. +- Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function itself + at the call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) +- Error recovery: Missing calls to End(), pass the assert, should not lead to crashes or to the fallback Debug window + appearing on screen, (#1651). - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. - Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. diff --git a/imgui.cpp b/imgui.cpp index 1629ebac..f33d7d5e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3555,6 +3555,9 @@ void ImGui::EndFrame() return; IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); + g.FrameScopeActive = false; + g.FrameCountEnded = g.FrameCount; + // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) { @@ -3567,9 +3570,15 @@ void ImGui::EndFrame() if (g.CurrentWindowStack.Size != 1) { if (g.CurrentWindowStack.Size > 1) + { IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING + End(); + } else + { IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } } // Hide implicit/fallback "Debug" window if it hasn't been used @@ -3665,9 +3674,6 @@ void ImGui::EndFrame() g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); - - g.FrameScopeActive = false; - g.FrameCountEnded = g.FrameCount; } void ImGui::Render() @@ -5251,6 +5257,13 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, void ImGui::End() { ImGuiContext& g = *GImGui; + + if (g.CurrentWindowStack.Size <= 1 && g.FrameScopeActive) + { + IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); + return; // FIXME-ERRORHANDLING + } + ImGuiWindow* window = g.CurrentWindow; if (window->DC.ColumnsSet != NULL) From e21bc446847474681c70e564eda28a85f6e1ae51 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 09:57:25 +0100 Subject: [PATCH 054/195] Comments: fixed missing line in the "how a simple rendering function may look like" section (#2258) --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index f33d7d5e..ebb54903 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -259,6 +259,7 @@ CODE // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. for (int n = 0; n < draw_data->CmdListsCount; n++) { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) From 6b97ded438c6d4d81835cd01f81e2e372f0bbe90 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 10:57:57 +0100 Subject: [PATCH 055/195] Happy new year! & comments --- LICENSE.txt | 2 +- docs/README.md | 2 +- imgui.cpp | 130 +++++++++++++++++++++++++++++-------------------- imgui.h | 8 +-- 4 files changed, 83 insertions(+), 59 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 21b6ee7e..3b439aa4 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2018 Omar Cornut +Copyright (c) 2014-2019 Omar Cornut Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/README.md b/docs/README.md index e396a108..809f19f8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -236,7 +236,7 @@ The library started its life and is best known as "ImGui" only due to the fact t **How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?** -
**How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack.** +
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?** diff --git a/imgui.cpp b/imgui.cpp index ebb54903..82fcb9af 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7,9 +7,12 @@ // Releases change-log at https://github.com/ocornut/imgui/releases // Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269 + // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. +// See LICENSE.txt for copyright and licensing details (standard MIT License). // This library is free but I need your support to sustain development and maintenance. -// If you work for a company, please consider financial support, see README. For individuals: https://www.patreon.com/imgui +// Businesses: you can support continued maintenance and development via support contracts or sponsoring, see docs/README. +// Individuals: you can support continued maintenance and development via donations or Patreon https://www.patreon.com/imgui. // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without @@ -26,17 +29,17 @@ DOCUMENTATION - MISSION STATEMENT - END-USER GUIDE - PROGRAMMER GUIDE (read me!) - - Read first - - How to update to a newer version of Dear ImGui - - Getting started with integrating Dear ImGui in your code/engine - - This is how a simple application may look like (2 variations) - - This is how a simple rendering function may look like - - Using gamepad/keyboard navigation controls + - Read first. + - How to update to a newer version of Dear ImGui. + - Getting started with integrating Dear ImGui in your code/engine. + - This is how a simple application may look like (2 variations). + - This is how a simple rendering function may look like. + - Using gamepad/keyboard navigation controls. - API BREAKING CHANGES (read me when you update!) - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS - How can I tell whether to dispatch mouse/keyboard to imgui or to my application? - How can I display an image? What is ImTextureID, how does it works? - - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack. + - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack. - How can I use my own math types instead of ImVec2/ImVec4? - How can I load a different font than the default? - How can I easily use icons in my application? @@ -84,19 +87,19 @@ CODE MISSION STATEMENT ================= - - Easy to use to create code-driven and data-driven tools - - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools - - Easy to hack and improve - - Minimize screen real-estate usage - - Minimize setup and maintenance - - Minimize state storage on user side - - Portable, minimize dependencies, run on target (consoles, phones, etc.) - - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window, - opening a tree node for the first time, etc. but a typical frame should not allocate anything) + - Easy to use to create code-driven and data-driven tools. + - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. + - Easy to hack and improve. + - Minimize screen real-estate usage. + - Minimize setup and maintenance. + - Minimize state storage on user side. + - Portable, minimize dependencies, run on target (consoles, phones, etc.). + - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,. + opening a tree node for the first time, etc. but a typical frame should not allocate anything). Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: - - Doesn't look fancy, doesn't animate - - Limited layout features, intricate layouts are typically crafted in code + - Doesn't look fancy, doesn't animate. + - Limited layout features, intricate layouts are typically crafted in code. END-USER GUIDE @@ -126,16 +129,29 @@ CODE PROGRAMMER GUIDE ================ - READ FIRST + READ FIRST: - Read the FAQ below this section! - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - - You can learn about immediate-mode GUI principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861 - See README.md for more links describing the IMGUI paradigm. Dear ImGui is an implementation of the IMGUI paradigm. - - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. + - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links docs/README.md. + - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. + For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, + where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. + - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. + - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). + If you get an assert, read the messages and comments around the assert. + - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. + - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. + See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. + However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. + - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). + + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI: - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) - Or maintain your own branch where you have imconfig.h modified. @@ -145,7 +161,7 @@ CODE likely be a comment about it. Please report any issue to the GitHub page! - Try to keep your copy of dear imgui reasonably up to date. - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE: - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. - Add the Dear ImGui source files to your projects or using your preferred build system. @@ -158,8 +174,8 @@ CODE - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. - HOW A SIMPLE APPLICATION MAY LOOK LIKE - EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder) + HOW A SIMPLE APPLICATION MAY LOOK LIKE: + EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder). // Application init: create a dear imgui context, setup some options, load fonts ImGui::CreateContext(); @@ -194,8 +210,8 @@ CODE ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); - HOW A SIMPLE APPLICATION MAY LOOK LIKE - EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE + HOW A SIMPLE APPLICATION MAY LOOK LIKE: + EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE. // Application init: create a dear imgui context, setup some options, load fonts ImGui::CreateContext(); @@ -249,12 +265,12 @@ CODE // Shutdown ImGui::DestroyContext(); - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE: void void MyImGuiRenderFunction(ImDrawData* draw_data) { // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled - // TODO: Setup viewport using draw_data->DisplaySize + // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. for (int n = 0; n < draw_data->CmdListsCount; n++) @@ -468,7 +484,7 @@ CODE - the signature of the io.RenderDrawListsFn handler has changed! old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). - argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' + parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. @@ -501,9 +517,9 @@ CODE - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. - font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..> - became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; - you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. + font init: { const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>; } + became: { unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; } + 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. (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) @@ -625,7 +641,7 @@ CODE Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. - Q: How can I have multiple widgets with the same label or without a label? + Q: How can I have multiple widgets with the same label or with an empty label? Q: I have multiple widgets with the same label, and only the first one works. Why is that? A: A primer on labels and the ID Stack... @@ -647,6 +663,9 @@ CODE Begin("MyWindow"); Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK") End(); + Begin("MyOtherWindow"); + Button("OK"); // Label = "OK", ID = hash of ("MyOtherWindow", "OK") + End(); - If you have a same ID twice in the same location, you'll have a conflict: @@ -686,47 +705,48 @@ CODE within the same window. This is the most convenient way of distinguishing ID when iterating and creating many UI elements programmatically. You can push a pointer, a string or an integer value into the ID stack. - Remember that ID are formed from the concatenation of _everything_ in the ID stack! + Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack. + At each level of the stack we store the seed used for items at this level of the ID stack. - Begin("Window"); + Begin("Window"); for (int i = 0; i < 100; i++) { - PushID(i); // Push i to the id tack - Button("Click"); // Label = "Click", ID = Hash of ("Window", i, "Click") + PushID(i); // Push i to the id tack + Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click") PopID(); } for (int i = 0; i < 100; i++) { MyObject* obj = Objects[i]; PushID(obj); - Button("Click"); // Label = "Click", ID = Hash of ("Window", obj pointer, "Click") + Button("Click"); // Label = "Click", ID = hash of ("Window", obj pointer, "Click") PopID(); } for (int i = 0; i < 100; i++) { MyObject* obj = Objects[i]; PushID(obj->Name); - Button("Click"); // Label = "Click", ID = Hash of ("Window", obj->Name, "Click") + Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click") PopID(); } End(); - - More example showing that you can stack multiple prefixes into the ID stack: + - You can stack multiple prefixes into the ID stack: - Button("Click"); // Label = "Click", ID = hash of (..., "Click") + Button("Click"); // Label = "Click", ID = hash of (..., "Click") PushID("node"); - Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") + Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") PushID(my_ptr); - Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click") + Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click") PopID(); PopID(); - Tree nodes implicitly creates a scope for you by calling PushID(). - Button("Click"); // Label = "Click", ID = hash of (..., "Click") - if (TreeNode("node")) + Button("Click"); // Label = "Click", ID = hash of (..., "Click") + if (TreeNode("node")) // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag) { - Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") + Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") TreePop(); } @@ -746,7 +766,8 @@ CODE ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() - Default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code. + Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code. + (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.) (Read the 'misc/fonts/README.txt' file for more details about font loading.) New programmers: remember that in C/C++ and most programming languages if you want to use a @@ -758,6 +779,7 @@ CODE Q: How can I easily use icons in my application? A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your strings. + You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment. (Read the 'misc/fonts/README.txt' file for more details about icons font loading.) Q: How can I load multiple fonts? @@ -847,10 +869,12 @@ CODE Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). Q: How can I help? - A: - If you are experienced with Dear ImGui and C++, look at the github issues, or docs/TODO.txt and see how you want/can help! - - Convince your company to sponsor/fund development! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README. + A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt + and see how you want to help and can help! + - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui. + - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README. - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. - You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers. + You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1902). Visuals are ideal as they inspire other programmers. But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). diff --git a/imgui.h b/imgui.h index 98e34e19..081cd5d0 100644 --- a/imgui.h +++ b/imgui.h @@ -3,7 +3,7 @@ // See imgui.cpp file for documentation. // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. -// Read 'Programmer guide' in imgui.cpp for notes on how to setup ImGui in your codebase. +// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui /* @@ -94,11 +94,11 @@ struct ImDrawVert; // A single vertex (20 bytes by default, ove 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 ImFontConfig; // Configuration data when adding a font or merging fonts -struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*obsolete* please avoid using) +struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) #ifndef ImTextureID typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) #endif -struct ImGuiContext; // ImGui context (opaque) +struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) struct ImGuiIO; // Main configuration and I/O between your application and ImGui struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) struct ImGuiListClipper; // Helper to manually clip large list of items @@ -113,7 +113,7 @@ struct ImGuiTextBuffer; // Helper to hold and append into a text buf // Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) -typedef unsigned short ImWchar; // Character for keyboard input/display +typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings. typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for Set*() typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type From c738f9ef92af3f84702e781686954422abaebfa9 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 11:03:56 +0100 Subject: [PATCH 056/195] InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) --- docs/CHANGELOG.txt | 1 + imgui_demo.cpp | 2 +- imgui_widgets.cpp | 7 +++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5d7bad6a..df5b685b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,7 @@ Other Changes: This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. +- InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) - Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function itself at the call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) - Error recovery: Missing calls to End(), pass the assert, should not lead to crashes or to the fallback Debug window diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9e7b748b..a5f8f86c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -480,7 +480,7 @@ static void ShowDemoWindowWidgets() ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); static float f0 = 0.001f; - ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); static double d0 = 999999.00000001; ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 367b9bb6..1b764e30 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2666,14 +2666,17 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p PopItemWidth(); // Step buttons + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + if (extra_flags & ImGuiInputTextFlags_ReadOnly) + button_flags |= ImGuiButtonFlags_Disabled; SameLine(0, style.ItemInnerSpacing.x); - if (ButtonEx("-", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) + if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) { DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); value_changed = true; } SameLine(0, style.ItemInnerSpacing.x); - if (ButtonEx("+", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) + if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) { DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); value_changed = true; From acacd93836485c47de71a2e6a6cd3488c0ccbe45 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 11:08:14 +0100 Subject: [PATCH 057/195] Renamed extra_flags to flags in InputXXX parameters. --- imgui.h | 31 +++++++++---------- imgui_widgets.cpp | 76 +++++++++++++++++++++++------------------------ 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/imgui.h b/imgui.h index 081cd5d0..08cd8504 100644 --- a/imgui.h +++ b/imgui.h @@ -433,19 +433,20 @@ namespace ImGui // Widgets: Input with Keyboard // - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h + // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x @@ -1413,10 +1414,10 @@ namespace ImGui // OBSOLETED in 1.63 (from Aug 2018) static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.61 (from Apr 2018) - IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! - IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! + IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0); // OBSOLETED in 1.60 (from Dec 2017) static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1b764e30..18567602 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2633,7 +2633,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c return false; } -bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2650,9 +2650,9 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format); bool value_changed = false; - if ((extra_flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) - extra_flags |= ImGuiInputTextFlags_CharsDecimal; - extra_flags |= ImGuiInputTextFlags_AutoSelectAll; + if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= ImGuiInputTextFlags_CharsDecimal; + flags |= ImGuiInputTextFlags_AutoSelectAll; if (step != NULL) { @@ -2661,13 +2661,13 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() PushID(label); PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); - if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view + if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format); PopItemWidth(); // Step buttons ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; - if (extra_flags & ImGuiInputTextFlags_ReadOnly) + if (flags & ImGuiInputTextFlags_ReadOnly) button_flags |= ImGuiButtonFlags_Disabled; SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) @@ -2689,14 +2689,14 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p } else { - if (InputText(label, buf, IM_ARRAYSIZE(buf), extra_flags)) + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format); } return value_changed; } -bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -2711,7 +2711,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in for (int i = 0; i < components; i++) { PushID(i); - value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, extra_flags); + value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, flags); SameLine(0, g.Style.ItemInnerSpacing.x); PopID(); PopItemWidth(); @@ -2724,88 +2724,88 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in return value_changed; } -bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) { - extra_flags |= ImGuiInputTextFlags_CharsScientific; - return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags); + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, flags); } -bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) { - return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); } -bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) { - return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); } -bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags) { - return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); } // Prefer using "const char* format" directly, which is more flexible and consistent with other API. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags) { char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputFloat(label, v, step, step_fast, format, extra_flags); + return InputFloat(label, v, step, step_fast, format, flags); } -bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags) { char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); } -bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags) { char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); } -bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags) +bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags) { char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); } #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags) +bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) { // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. - const char* format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; - return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags); + const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, flags); } -bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags) +bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) { - return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", extra_flags); + return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags); } -bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags) +bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags) { - return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", extra_flags); + return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags); } -bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags) +bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) { - return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", extra_flags); + return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags); } -bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) { - extra_flags |= ImGuiInputTextFlags_CharsScientific; - return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags); + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, flags); } //------------------------------------------------------------------------- From c017a4fb5f92a77ba05f24b666a62b210119c37b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 14:28:49 +0100 Subject: [PATCH 058/195] Moved guidelines to issue #2261 to Pin and increase visibility for now. --- .github/CONTRIBUTING.md | 44 +------------------------------- .github/issue_template.md | 23 +++++++++-------- .github/pull_request_template.md | 17 +++++++----- 3 files changed, 24 insertions(+), 60 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5bbd8e15..84a39d29 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,43 +1 @@ -## How to create an Issue - -Hello! - -You may use the Issue Tracker to submit bug reports, feature requests or suggestions. You may ask for help or advice as well. However please read this wall of text before doing so. The amount of incomplete or ambiguous requests due to people not following those guidelines is often overwhelming. Please do your best to clarify your request. Thank you! - -**IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/DISPLAYING/ADDING FONTS/WIRING INPUTS** -- Please post on the "Getting Started" Discourse forum: https://discourse.dearimgui.org/c/getting-started - -**Prerequisites for new users of dear imgui:** -- Please read the FAQ in imgui.cpp. -- Please read misc/fonts/README.txt if your question relates to fonts or text. -- Please run ImGui::ShowDemoWindow() to explore the demo and its sources. -- Please use the Search function of GitHub to look for similar issues. You may also browse issues by tags. -- Please use the Search function of your IDE to search in the code for comments related to your situation. -- If you get a assert, use a debugger to locate the line triggering it and read the comments around the assert. - -**Guidelines to report an issue or ask a question:** -- Please provide your imgui version number. -- Please state if you have made substantial modifications to your copy of imgui. -- Try to be explicit with your Goals, your Expectations and what you have Tried. What you have in mind or in your code is not obvious to other people. People frequently discuss problems without first mentioning their goal. -- If you are discussing an assert or a crash, please provide a debugger callstack. Never state "it crashes" without additional information. If you don't know how to use a debugger and retrieve a callstack, learning about it will be useful. -- Please make sure that your compilation settings have asserts enabled. Calls to IM_ASSERT() are scattered in the code to help catch common issues. By default IM_ASSERT() calls the standard assert() function. To verify that your asserts are enabled, add the line `IM_ASSERT(false);` in your main() function. Your application should display an error message and abort. If your application report an error, it means that your asserts are disabled. Please make sure they are enabled. -- When discussing issues related to rendering or inputs, please state the OS/back-end/renderer you are using. Please state if you are using a vanilla copy of the example back-ends (imgui_impl_XXX files), or a modified one, or if you built your own. -- Please provide a Minimal, Complete and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem. An ideal submission includes a small piece of code that anyone can paste in one of the examples/ application (e.g. in main.cpp or imgui_demo.cpp) to understand and reproduce it. Narrowing your problem to its shortest and purest form is the easiest way to understand it. Please test your shortened code to ensure it actually exhibit the problem. Often while creating the MCVE you will end up solving the problem! Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time. -- Try to attach screenshots to clarify the context. They often convey useful information that are omitted by the description. You can drag pictures/files here (prefer github attachments over 3rd party hosting). -- When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc.). - -**Some unfortunate words of warning** -- If you are or were involved in cheating schemes (e.g. DLL injection) for competitive online multi-player games, please don't post here. We won't answer and you will be blocked. We've had too many of you. -- Due to frequent abuse of this service from aforementioned users, if your GitHub account is anonymous and was created five minutes ago please understand that your post will receive more scrutiny and incomplete questions may be dismissed. - -If you have been using dear imgui for a while or have been using C/C++ for several years or have demonstrated good behavior here, it is ok to not fullfill every item to the letter. Those are guidelines and experienced users or members of the community will know which information are useful in a given context. - -## How to create an Pull Request -- Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. -- When adding a feature, please describe the usage context (how you intend to use it, why you need it, etc.). -- When fixing a warning or compilation problem, please post the compiler log and specify the version and OS you are using. -- Try to attach screenshots to clarify the context and demonstrate the feature at a glance. You can drag pictures/files here (prefer github attachments over 3rd party hosting). -- Make sure your code follows the coding style already used in imgui (spaces instead of tabs, "local_variable", "FunctionName", "MemberName", etc.). We don't use modern C++ idioms and can compile without C++11. -- Make sure you create a branch for the pull request. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR (we can still cherry-pick individual commits). - -Thank you for reading! +Please read https://github.com/ocornut/imgui/issues/2261 diff --git a/.github/issue_template.md b/.github/issue_template.md index 38a59532..2ce90bee 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -1,11 +1,12 @@ (Click "Preview" to turn any http URL into a clickable link) -1. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/DISPLAYING/ADDING FONTS/WIRING INPUTS, please post on the "Getting Started" Discourse forum: -https://discourse.dearimgui.org/c/getting-started +1. PLEASE CAREFULLY READ: +https://github.com/ocornut/imgui/issues/2261 -2. You may use this Issue Tracker to ask for help and submit bug reports, feature requests or suggestions that don't fit in any category of (1). PLEASE CAREFULLY READ THE CONTRIBUTING DOCUMENT before submitting any issue: https://github.com/ocornut/imgui/blob/master/.github/CONTRIBUTING.md +2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/DISPLAYING/ADDING FONTS, please post on the "Getting Started" Discourse forum: +https://discourse.dearimgui.org/c/getting-started -3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the CONTRIBUTING.md file linked above. +3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1). 4. Delete points 1-4 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue. @@ -21,19 +22,21 @@ Branch: XXX _(master/viewport/docking/etc.)_ **Back-end/Renderer/Compiler/OS** Back-ends: imgui_impl_XXX.cpp + imgui_impl_XXX.cpp _(or specify if using a custom engine/back-end)_ -Compiler: XXX _(if the question is related to building)_ +Compiler: XXX _(if the question is related to building or platform specific features)_ Operating System: XXX -**My Issue/Question:** _(please provide context)_ +**My Issue/Question:** + +XXX _(please provide as much context as possible)_ -XXX +**Screenshots/Video** -**Standalone, minimal, complete and verifiable example:** _(see CONTRIBUTING.md)_ +XXX _(you can drag files here)_ + +**Standalone, minimal, complete and verifiable example:** _(see https://github.com/ocornut/imgui/issues/2261)_ ``` // Please do not forget this! ImGui::Begin("Example Bug"); MoreCodeToExplainMyIssue(); ImGui::End(); ``` - -**Screenshots/Video** _(you can drag files here)_ diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 65ebcf24..ad66ea6f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,12 @@ -- Please read https://github.com/ocornut/imgui/blob/master/.github/CONTRIBUTING.md -- Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. -- When adding a feature, please describe the usage context (how you intend to use it, why you need it, etc.). -- When adding a feature, try to attach screenshots/gifs to clarify the context and demonstrate the feature at a glance. -- When fixing a warning or compilation problem, post the compiler log and specify the version and OS you are using. -- Make sure your code follows the coding style already used in the codebase (4 spaces identation, no tabs, `type* name`, `local_variable`, `FunctionName()`, `MemberName`, `// Text Comment`, `//CodeComment()`, etc.). We don't use modern C++ idioms, we don't use C++ style cast, we don't use C++ headers, and we can compile without a C++11 compatible compiler. -- Make sure you create a branch for the pull request. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR. +(Click "Preview" to turn any http URL into a clickable link) + +1. PLEASE CAREFULLY READ: +https://github.com/ocornut/imgui/issues/2261 + +2. PLEASE MAKE SURE YOU HAVE READ: +https://github.com/ocornut/imgui/issues/2261 + +3. DID I MENTION YOU SHOULD READ THIS? +https://github.com/ocornut/imgui/issues/2261 (Clear this form before submitting your PR) From d9a4cbc4296bc6579b88b66b21bd27f84f0d2d27 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 16:04:13 +0100 Subject: [PATCH 059/195] Examples: Comments about GLFW/SDL versions --- examples/imgui_impl_glfw.cpp | 1 + examples/imgui_impl_sdl.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 6c6f452d..0ff27446 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -1,6 +1,7 @@ // dear imgui: Platform Binding for GLFW // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) +// (Requires: GLFW 3.1+) // Implemented features: // [X] Platform: Clipboard support. diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index fbd420a6..54ddc282 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -1,6 +1,7 @@ // dear imgui: Platform Binding for SDL2 // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) +// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.) // Implemented features: // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. @@ -49,7 +50,6 @@ #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) -#define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5) #if !SDL_HAS_VULKAN static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; #endif From e194219f2e2e4b51099d45ed50017804efa9a57b Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 17:01:08 +0100 Subject: [PATCH 060/195] Renamed ImGuiDockFamily to ImGuiWindowClass. Renamed CompatibleWithClassZero to DockingAllowUnclassed. (#2109) --- docs/CHANGELOG.txt | 2 +- docs/TODO.txt | 2 +- imgui.cpp | 46 +++++++++++++++++++++++----------------------- imgui.h | 21 ++++++++++----------- imgui_demo.cpp | 2 +- imgui_internal.h | 12 ++++++------ 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8fb21669..d4b0ea76 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -38,7 +38,7 @@ HOW TO UPDATE? Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`. - Added DockSpace() API. - Added ImGuiDockNodeFlags flags for DockSpace(). - - Added SetNextWindowDock(), SetNextWindowDockFamily() API. + - Added SetNextWindowDock(), SetNextWindowClass() API. - Added GetWindowDockId(), IsWindowDocked() API. - Added ImGuiWindowFlags_NoDocking window flag to disable the possibility for a window to be docked. Popup, Menu and Child windows always have the ImGuiWindowFlags_NoDocking flag set. diff --git a/docs/TODO.txt b/docs/TODO.txt index 3594d888..4fd3fad4 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -145,7 +145,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: B- tab bar: make selected tab always shows its full title? - dock: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8) - dock: B- nav: design interactions so nav controls can dock/undock - - dock: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockFlags_Locked?) + - dock: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockNodeFlags_Locked?) - dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node! - dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button) - dock: B- option to remember undocked window size? (instead of keeping their docked size) (relate to #2104) diff --git a/imgui.cpp b/imgui.cpp index 4f2ff59d..aaa07d05 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5084,7 +5084,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); } - window->DockFamily = g.NextWindowData.DockFamily; + window->WindowClass = g.NextWindowData.WindowClass; if (g.NextWindowData.CollapsedCond) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.FocusCond) @@ -6531,10 +6531,10 @@ void ImGui::SetNextWindowDockId(ImGuiID id, ImGuiCond cond) g.NextWindowData.DockId = id; } -void ImGui::SetNextWindowDockFamily(const ImGuiDockFamily* family) +void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class) { ImGuiContext& g = *GImGui; - g.NextWindowData.DockFamily = *family; + g.NextWindowData.WindowClass = *window_class; } // In window space (not screen space!) @@ -10679,7 +10679,7 @@ struct ImGuiDockNodeUpdateScanResults ImGuiDockNode* CentralNode; ImGuiDockNode* FirstNodeWithWindows; int CountNodesWithWindows; - //ImGuiDockFamily DockFamilyForMerges; + //ImGuiWindowClass WindowClassForMerges; ImGuiDockNodeUpdateScanResults() { CentralNode = FirstNodeWithWindows = NULL; CountNodesWithWindows = 0; } }; @@ -10802,16 +10802,16 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (node->LastFocusedNodeID == 0 && results.FirstNodeWithWindows != NULL) node->LastFocusedNodeID = results.FirstNodeWithWindows->ID; - // Copy the dock family from of our window so it can be used for proper dock filtering. - // When node has mixed windows, prioritize the family with the most constraint (CompatibleWithNeutral = false) as the reference to copy. + // Copy the window class from of our first window so it can be used for proper dock filtering. + // When node has mixed windows, prioritize the class with the most constraint (CompatibleWithClassZero = false) as the reference to copy. // FIXME-DOCK: We don't recurse properly, this code could be reworked to work from DockNodeUpdateScanRec. if (ImGuiDockNode* first_node_with_windows = results.FirstNodeWithWindows) { - node->DockFamily = first_node_with_windows->Windows[0]->DockFamily; + node->WindowClass = first_node_with_windows->Windows[0]->WindowClass; for (int n = 1; n < first_node_with_windows->Windows.Size; n++) - if (first_node_with_windows->Windows[n]->DockFamily.CompatibleWithFamilyZero == false) + if (first_node_with_windows->Windows[n]->WindowClass.DockingAllowUnclassed == false) { - node->DockFamily = first_node_with_windows->Windows[n]->DockFamily; + node->WindowClass = first_node_with_windows->Windows[n]->WindowClass; break; } } @@ -11272,13 +11272,13 @@ static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_win if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; - ImGuiDockFamily* host_family = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->DockFamily : &host_window->DockFamily; - ImGuiDockFamily* payload_family = &payload->DockFamily; - if (host_family->FamilyId != payload_family->FamilyId) + ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass; + ImGuiWindowClass* payload_class = &payload->WindowClass; + if (host_class->ClassId != payload_class->ClassId) { - if (host_family->FamilyId != 0 && host_family->CompatibleWithFamilyZero && payload_family->FamilyId == 0) + if (host_class->ClassId != 0 && host_class->DockingAllowUnclassed && payload_class->ClassId == 0) return true; - if (payload_family->FamilyId != 0 && payload_family->CompatibleWithFamilyZero && host_family->FamilyId == 0) + if (payload_class->ClassId != 0 && payload_class->DockingAllowUnclassed && host_class->ClassId == 0) return true; return false; } @@ -11928,7 +11928,7 @@ void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) // Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a CentralNode by default. // The Central Node is always displayed even when empty and shrink/extend according to the requested size of its neighbors. -void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dockspace_flags, const ImGuiDockFamily* dock_family) +void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class) { ImGuiContext* ctx = GImGui; ImGuiContext& g = *ctx; @@ -11943,7 +11943,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc node->IsCentralNode = true; } node->Flags = dockspace_flags; - node->DockFamily = dock_family ? *dock_family : ImGuiDockFamily(); + node->WindowClass = window_class ? *window_class : ImGuiWindowClass(); // When a Dockspace transitioned form implicit to explicit this may be called a second time // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again. @@ -12006,7 +12006,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc // The limitation with this call is that your window won't have a menu bar. // Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function. // So if you want a menu bar you need to repeat this code manually ourselves. As with advanced other Docking API, we may change this function signature. -ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiDockFamily* dock_family) +ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class) { if (viewport == NULL) viewport = GetMainViewport(); @@ -12031,7 +12031,7 @@ ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags PopStyleVar(3); ImGuiID dockspace_id = GetID("Dockspace"); - DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags, dock_family); + DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags, window_class); End(); return dockspace_id; @@ -12299,7 +12299,7 @@ void ImGui::DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_docks IM_ASSERT((in_window_remap_pairs->Size % 2) == 0); // Duplicate entire dock - // FIXME: When overwriting dst_dockspace_id, windows that aren't part of our dockspace family but that are docked in a same node will be split apart, + // FIXME: When overwriting dst_dockspace_id, windows that aren't part of our dockspace window class but that are docked in a same node will be split apart, // whereas we could attempt to at least keep them together in a new, same floating node. ImVector node_remap_pairs; DockBuilderCopyNode(src_dockspace_id, dst_dockspace_id, &node_remap_pairs); @@ -13126,7 +13126,7 @@ static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } else if (sscanf(line, "DockId=0x%X,%d", &u1, &i) == 2) { settings->DockId = u1; settings->DockOrder = (short)i; } else if (sscanf(line, "DockId=0x%X", &u1) == 1) { settings->DockId = u1; settings->DockOrder = -1; } - else if (sscanf(line, "DockFamilyId=0x%X", &u1) == 1) { settings->DockFamilyId = u1; } + else if (sscanf(line, "ClassId=0x%X", &u1) == 1) { settings->ClassId = u1; } } static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) @@ -13153,7 +13153,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting settings->ViewportPos = window->ViewportPos; IM_ASSERT(window->DockNode == NULL || window->DockNode->ID == window->DockId); settings->DockId = window->DockId; - settings->DockFamilyId = window->DockFamily.FamilyId; + settings->ClassId = window->WindowClass.ClassId; settings->DockOrder = window->DockOrder; settings->Collapsed = window->Collapsed; } @@ -13184,8 +13184,8 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting buf->appendf("DockId=0x%08X\n", settings->DockId); else buf->appendf("DockId=0x%08X,%d\n", settings->DockId, settings->DockOrder); - if (settings->DockFamilyId != 0) - buf->appendf("DockFamilyId=0x%08X\n", settings->DockFamilyId); + if (settings->ClassId != 0) + buf->appendf("ClassId=0x%08X\n", settings->ClassId); } buf->appendf("\n"); } diff --git a/imgui.h b/imgui.h index 9404c928..4873222a 100644 --- a/imgui.h +++ b/imgui.h @@ -15,7 +15,7 @@ Index of this file: // Flags & Enumerations // ImGuiStyle // ImGuiIO -// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiDockFamily) +// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiWindowClass) // Obsolete functions // Helpers (ImVector, ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) @@ -102,7 +102,7 @@ struct ImColor; // Helper functions to create a color that c typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) #endif struct ImGuiContext; // ImGui context (opaque) -struct ImGuiDockFamily; // Docking family for dock filtering +struct ImGuiWindowClass; // Window class/family for docking filtering or high-level identifiation of windows by user struct ImGuiIO; // Main configuration and I/O between your application and ImGui struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) struct ImGuiListClipper; // Helper to manually clip large list of items @@ -578,10 +578,10 @@ namespace ImGui // Note: you DO NOT need to call DockSpace() to use most Docking facilities! // To dock windows: hold SHIFT anywhere while moving windows (if io.ConfigDockingWithShift == true) or drag windows from their title bar (if io.ConfigDockingWithShift = false) // Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details. - IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiDockFamily* dock_family = NULL); - IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags dockspace_flags = 0, const ImGuiDockFamily* dock_family = NULL); + IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); + IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags dockspace_flags = 0, const ImGuiWindowClass* window_class = NULL); IMGUI_API void SetNextWindowDockId(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) - IMGUI_API void SetNextWindowDockFamily(const ImGuiDockFamily* dock_family); // set next window user type (docking filters by same user_type) + IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class / user type (docking filters by same user_type) IMGUI_API ImGuiID GetWindowDockId(); IMGUI_API bool IsWindowDocked(); // is current window docked into another window? @@ -1470,14 +1470,13 @@ struct ImGuiPayload bool IsDelivery() const { return Delivery; } }; -// [BETA] For SetNextWindowDockFamily() and DockSpace() function -struct ImGuiDockFamily +// [BETA] Rarely used, very advanced uses only. Use with SetNextWindowClass() and DockSpace() functions. +struct ImGuiWindowClass { - ImGuiID FamilyId; // 0 = unaffiliated - bool CompatibleWithFamilyZero; // true = can be docked/merged with an unaffiliated window + ImGuiID ClassId; // User data. 0 = Default class (unclassed) + bool DockingAllowUnclassed; // true = can be docked/merged with an unclassed window - ImGuiDockFamily() { FamilyId = 0; CompatibleWithFamilyZero = true; } - ImGuiDockFamily(ImGuiID family_id, bool compatible_with_family_zero = true) { FamilyId = family_id; CompatibleWithFamilyZero = compatible_with_family_zero; } + ImGuiWindowClass() { ClassId = 0; DockingAllowUnclassed = true; } }; //----------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5fbae2c5..317e59dc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1541,7 +1541,7 @@ static void ShowDemoWindowWidgets() if (test_window) { // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. - // Could we fix this through an ImGuiDockFamily feature? Or an API call to tag our parent as "don't skip items"? + // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? ImGui::Begin("Title bar Hovered/Active tests", &test_window); if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() { diff --git a/imgui_internal.h b/imgui_internal.h index 7578f842..687b53bc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -566,11 +566,11 @@ struct ImGuiWindowSettings ImVec2 ViewportPos; ImGuiID ViewportId; ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none. - ImGuiID DockFamilyId; // ID of dock family if specified + ImGuiID ClassId; // ID of window class if specified short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible. bool Collapsed; - ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ViewportPos = ImVec2(0, 0); ViewportId = DockId = DockFamilyId = 0; DockOrder = -1; Collapsed = false; } + ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ViewportPos = ImVec2(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = false; } }; struct ImGuiSettingsHandler @@ -734,7 +734,7 @@ struct ImGuiNextWindowData float BgAlphaVal; ImGuiID ViewportId; ImGuiID DockId; - ImGuiDockFamily DockFamily; + ImGuiWindowClass WindowClass; ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. ImGuiNextWindowData() @@ -754,7 +754,7 @@ struct ImGuiNextWindowData void Clear() { PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0; - DockFamily = ImGuiDockFamily(); + WindowClass = ImGuiWindowClass(); } }; @@ -781,7 +781,7 @@ struct ImGuiDockNode ImVec2 Size; // Current size ImVec2 SizeRef; // [Split node only] Last explicitly written-to size (overridden when using a splitter affecting the node), used to calculate Size. int SplitAxis; // [Split node only] Split axis (X or Y) - ImGuiDockFamily DockFamily; + ImGuiWindowClass WindowClass; ImGuiWindow* HostWindow; ImGuiWindow* VisibleWindow; @@ -1201,6 +1201,7 @@ struct IMGUI_API ImGuiWindow char* Name; ImGuiID ID; // == ImHash(Name) ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_ + ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass() ImGuiViewportP* Viewport; // Always set in Begin(), only inactive windows may have a NULL value here ImGuiID ViewportId; // We backup the viewport id (since the viewport may disappear or never be created if the window is inactive) ImVec2 ViewportPos; // We backup the viewport position (since the viewport may disappear or never be created if the window is inactive) @@ -1247,7 +1248,6 @@ struct IMGUI_API ImGuiWindow ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use. ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. - ImGuiDockFamily DockFamily; // set with SetNextWindowDockFamily() ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack From 4ea9fdbbea77408e3eda8e233ffbaca4c65e82fb Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 17:04:39 +0100 Subject: [PATCH 061/195] Docking: Agressively assert when CentralNode is a not a leaf node in order to find our bug. --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index aaa07d05..c880763e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10695,6 +10695,7 @@ static void DockNodeUpdateScanRec(ImGuiDockNode* node, ImGuiDockNodeUpdateScanRe if (node->IsCentralNode) { IM_ASSERT(results->CentralNode == NULL); // Should be only one + IM_ASSERT(node->IsLeafNode() && "If you get this assert: your .ini file may have been damaged by an old bug. OR please submit repro of actions leading to this"); results->CentralNode = node; } if (results->CountNodesWithWindows > 1 && results->CentralNode != NULL) @@ -11916,7 +11917,7 @@ void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) dock_id = new_node->CentralNode->ID; else dock_id = new_node->LastFocusedNodeID; - } + } if (window->DockId == dock_id) return; From 5305c322422e787f4b327a45284c9d08cec3cc44 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 21 Dec 2018 19:12:24 +0100 Subject: [PATCH 062/195] Viewport: Reorder flags. Set owned viewport common decoration flags in Begin(). Moved code in UpdateViewportsEndFrame() before we introduce family/class based overrides. --- imgui.cpp | 76 +++++++++++++++++++++++++----------------------- imgui.h | 14 ++++----- imgui_internal.h | 2 +- 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f9a8a65f..f18c61aa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1010,7 +1010,8 @@ static void UpdateManualResize(ImGuiWindow* window, const ImVec2& si // Viewports const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHash("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter. static ImGuiViewportP* AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& platform_pos, const ImVec2& size, ImGuiViewportFlags flags); -static void UpdateViewports(); +static void UpdateViewportsNewFrame(); +static void UpdateViewportsEndFrame(); static void UpdateSelectWindowViewport(ImGuiWindow* window); static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport); static void SetCurrentViewport(ImGuiWindow* window, ImGuiViewportP* viewport); @@ -3352,7 +3353,7 @@ void ImGui::NewFrame() g.WindowsActiveCount = 0; g.ConfigFlagsForFrame = g.IO.ConfigFlags; - UpdateViewports(); + UpdateViewportsNewFrame(); // Setup current font, and draw list shared data // FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! @@ -3846,24 +3847,8 @@ void ImGui::EndFrame() } } - // Update user-facing viewport list - g.PlatformIO.MainViewport = g.Viewports[0]; - g.PlatformIO.Viewports.resize(0); - for (int i = 0; i < g.Viewports.Size; i++) - { - ImGuiViewportP* viewport = g.Viewports[i]; - viewport->LastPos = viewport->Pos; - if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) - continue; - if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)) // Will be destroyed in UpdatePlatformWindows() - continue; - if (i > 0) - IM_ASSERT(viewport->Window != NULL); - - // Add to user-facing list - g.PlatformIO.Viewports.push_back(viewport); - } - g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called + // Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some) + UpdateViewportsEndFrame(); // Sort the window list so that all child windows are after their parent // We cannot do that on FocusWindow() because childs may not exist yet @@ -5178,16 +5163,26 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetCurrentWindow(window); } - // Synchronize viewport --> window in case the platform window has been moved or resized from the OS/WM if (window->ViewportOwned) { + // Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM if (window->Viewport->PlatformRequestMove) window->Pos = window->Viewport->Pos; if (window->Viewport->PlatformRequestResize) window->Size = window->SizeFull = window->Viewport->Size; + // Update common viewport flags + ImGuiViewportFlags viewport_flags = (window->Viewport->Flags) & ~(ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration); + if (flags & ImGuiWindowFlags_Tooltip) + viewport_flags |= ImGuiViewportFlags_TopMost; + if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) != 0 || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) + viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon; + if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) + viewport_flags |= ImGuiViewportFlags_NoDecoration; + // We also tell the back-end that clearing the platform window won't be necessary, as our window is filling the viewport and we have disabled BgAlpha - window->Viewport->Flags |= ImGuiViewportFlags_NoRendererClear; + viewport_flags |= ImGuiViewportFlags_NoRendererClear; + window->Viewport->Flags = viewport_flags; } // Clamp position so window stays visible within its viewport or monitor @@ -7387,8 +7382,7 @@ static ImGuiViewportP* FindViewportHoveredFromPlatformWindowStack(const ImVec2 m return best_candidate; } -// Called in NewFrame() -static void ImGui::UpdateViewports() +static void ImGui::UpdateViewportsNewFrame() { ImGuiContext& g = *GImGui; IM_ASSERT(g.PlatformIO.Viewports.Size <= g.Viewports.Size); @@ -7540,6 +7534,27 @@ static void ImGui::UpdateViewports() IM_ASSERT(g.MouseViewport != NULL); } +// Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some) +static void ImGui::UpdateViewportsEndFrame() +{ + ImGuiContext& g = *GImGui; + g.PlatformIO.MainViewport = g.Viewports[0]; + g.PlatformIO.Viewports.resize(0); + for (int i = 0; i < g.Viewports.Size; i++) + { + ImGuiViewportP* viewport = g.Viewports[i]; + viewport->LastPos = viewport->Pos; + if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) + continue; + if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)) + continue; + if (i > 0) + IM_ASSERT(viewport->Window != NULL); + g.PlatformIO.Viewports.push_back(viewport); + } + g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called +} + // FIXME: We should ideally refactor the system to call this every frame (we currently don't) ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& pos, const ImVec2& size, ImGuiViewportFlags flags) { @@ -7734,19 +7749,6 @@ void ImGui::UpdatePlatformWindows() if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0 || viewport->Size.y <= 0) continue; - // Update common viewport flags for owned viewports - if (ImGuiWindow* window = viewport->Window) - { - ImGuiViewportFlags flags = viewport->Flags & ~(ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration); - if (window->Flags & ImGuiWindowFlags_Tooltip) - flags |= ImGuiViewportFlags_TopMost; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) != 0 || (window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) - flags |= ImGuiViewportFlags_NoTaskBarIcon; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) - flags |= ImGuiViewportFlags_NoDecoration; - viewport->Flags = flags; - } - // Create window bool is_new_platform_window = (viewport->PlatformWindowCreated == false); if (is_new_platform_window) diff --git a/imgui.h b/imgui.h index b0ad4ed4..b0f1dccc 100644 --- a/imgui.h +++ b/imgui.h @@ -989,8 +989,8 @@ enum ImGuiConfigFlags_ // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable. ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends) ImGuiConfigFlags_ViewportsNoTaskBarIcon = 1 << 11, // Disable task bars icons for all secondary viewports (will set ImGuiViewportFlags_NoTaskBarIcon on them) - ImGuiConfigFlags_ViewportsNoMerge = 1 << 12, // All floating windows will always create their own viewport and platform window. - ImGuiConfigFlags_ViewportsDecoration = 1 << 13, // FIXME [Broken] Enable platform decoration for all secondary viewports (will not set ImGuiViewportFlags_NoDecoration on them). This currently doesn't behave well in Windows because 1) By default the new window animation get in the way of our transitions, 2) It enable a minimum window size which tends to breaks resizing. You can workaround the later by setting style.WindowMinSize to a bigger value. + ImGuiConfigFlags_ViewportsDecoration = 1 << 12, // FIXME [Broken] Enable platform decoration for all secondary viewports (will not set ImGuiViewportFlags_NoDecoration on them). This currently doesn't behave well in Windows because 1) By default the new window animation get in the way of our transitions, 2) It enable a minimum window size which tends to breaks resizing. You can workaround the later by setting style.WindowMinSize to a bigger value. + ImGuiConfigFlags_ViewportsNoMerge = 1 << 13, // All floating windows will always create their own viewport and platform window. ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 14, // FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). Note that resizing the main window itself is up to your application. ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 15, // FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress. @@ -2217,11 +2217,11 @@ struct ImGuiPlatformIO enum ImGuiViewportFlags_ { ImGuiViewportFlags_None = 0, - ImGuiViewportFlags_NoDecoration = 1 << 0, // Platform Window: Disable platform decorations: title bar, borders, etc. - ImGuiViewportFlags_NoFocusOnAppearing = 1 << 1, // Platform Window: Don't take focus when created. - ImGuiViewportFlags_NoInputs = 1 << 2, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. - ImGuiViewportFlags_NoTaskBarIcon = 1 << 3, // Platform Window: Disable platform task bar icon (for popups, menus, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcons if set) - ImGuiViewportFlags_NoRendererClear = 1 << 4, // Platform Window: Renderer doesn't need to clear the framebuffer ahead. + ImGuiViewportFlags_NoDecoration = 1 << 0, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips) + ImGuiViewportFlags_NoTaskBarIcon = 1 << 1, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set) + ImGuiViewportFlags_NoFocusOnAppearing = 1 << 2, // Platform Window: Don't take focus when created. + ImGuiViewportFlags_NoInputs = 1 << 3, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. + ImGuiViewportFlags_NoRendererClear = 1 << 4, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely). ImGuiViewportFlags_TopMost = 1 << 5 // Platform Window: Display on top (for tooltips only) }; diff --git a/imgui_internal.h b/imgui_internal.h index 151b7a4b..fee712b9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -665,7 +665,7 @@ struct ImGuiViewportP : public ImGuiViewport short PlatformMonitor; bool PlatformWindowCreated; bool PlatformWindowMinimized; - ImGuiWindow* Window; // Set when the viewport is owned by a window + ImGuiWindow* Window; // Set when the viewport is owned by a window (and ImGuiViewportFlags_CanHostOtherWindows is NOT set) ImDrawList* OverlayDrawList; // For convenience, a draw list we can render to that's always rendered last (we use it to draw software mouse cursor when io.MouseDrawCursor is set) ImDrawData DrawDataP; ImDrawDataBuilder DrawDataBuilder; From 4a6f95acc881f09de2835a93273cf725801790e1 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 16:06:58 +0100 Subject: [PATCH 063/195] Viewport: Added Platform_UpdateWindow hook for general purpose: Rework Win32 code to reflect viewport flags changes into Win32 while the window is active. --- examples/imgui_impl_win32.cpp | 65 ++++++++++++++++++++++++++--------- imgui.cpp | 4 +++ imgui.h | 1 + 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index ef22fa47..fed43afd 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -431,33 +431,38 @@ struct ImGuiViewportDataWin32 ~ImGuiViewportDataWin32() { IM_ASSERT(Hwnd == NULL); } }; +static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style) +{ + if (flags & ImGuiViewportFlags_NoDecoration) + *out_style = WS_POPUP; + else + *out_style = WS_OVERLAPPEDWINDOW; + + if (flags & ImGuiViewportFlags_NoTaskBarIcon) + *out_ex_style = WS_EX_TOOLWINDOW; + else + *out_ex_style = WS_EX_APPWINDOW; + + if (flags & ImGuiViewportFlags_TopMost) + *out_ex_style |= WS_EX_TOPMOST; +} + static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) { ImGuiViewportDataWin32* data = IM_NEW(ImGuiViewportDataWin32)(); viewport->PlatformUserData = data; - bool no_decoration = (viewport->Flags & ImGuiViewportFlags_NoDecoration) != 0; - bool no_task_bar_icon = (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) != 0; - if (no_decoration) - { - data->DwStyle = WS_POPUP; - data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW; - } - else - { - data->DwStyle = WS_OVERLAPPEDWINDOW; - data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW; - } - if (viewport->Flags & ImGuiViewportFlags_TopMost) - data->DwExStyle |= WS_EX_TOPMOST; + // Select style and parent window + HWND parent_window = g_hWnd; + ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &data->DwStyle, &data->DwExStyle); // Create window RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); data->Hwnd = ::CreateWindowEx( - data->DwExStyle, _T("ImGui Platform"), _T("No Title Yet"), data->DwStyle, // Style, class name, window name - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area - g_hWnd, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param + data->DwExStyle, _T("ImGui Platform"), _T("Untitled"), data->DwStyle, // Style, class name, window name + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area + parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param data->HwndOwned = true; viewport->PlatformRequestResize = false; viewport->PlatformHandle = data->Hwnd; @@ -491,6 +496,31 @@ static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport) ::ShowWindow(data->Hwnd, SW_SHOW); } +static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport) +{ + // (Optional) Update Win32 style if it changed _after_ creation. + // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful. + ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData; + IM_ASSERT(data->Hwnd != 0); + DWORD new_style; + DWORD new_ex_style; + ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style); + + // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows) + if (data->DwStyle != new_style || data->DwExStyle != new_ex_style) + { + data->DwStyle = new_style; + data->DwExStyle = new_ex_style; + ::SetWindowLong(data->Hwnd, GWL_STYLE, data->DwStyle); + ::SetWindowLong(data->Hwnd, GWL_EXSTYLE, data->DwExStyle); + RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; + ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen + ::SetWindowPos(data->Hwnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + ::ShowWindow(data->Hwnd, SW_SHOWNA); // This is necessary when we alter the style + viewport->PlatformRequestMove = viewport->PlatformRequestResize = true; + } +} + static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport) { ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData; @@ -695,6 +725,7 @@ static void ImGui_ImplWin32_InitPlatformInterface() platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized; platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle; platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha; + platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow; platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI #if HAS_WIN32_IME diff --git a/imgui.cpp b/imgui.cpp index f18c61aa..681d8210 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7794,6 +7794,10 @@ void ImGui::UpdatePlatformWindows() g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport->Alpha); viewport->LastAlpha = viewport->Alpha; + // Optional, general purpose call to allow the back-end to perform general book-keeping even if things haven't changed. + if (g.PlatformIO.Platform_UpdateWindow) + g.PlatformIO.Platform_UpdateWindow(viewport); + if (is_new_platform_window) { // On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late) diff --git a/imgui.h b/imgui.h index b0f1dccc..6d7f8dd2 100644 --- a/imgui.h +++ b/imgui.h @@ -2186,6 +2186,7 @@ struct ImGuiPlatformIO bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp); void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* title); void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // (Optional) Setup window transparency + void (*Platform_UpdateWindow)(ImGuiViewport* vp); // (Optional) Called in UpdatePlatforms(). Optional hook to allow the platform back-end from doing general book-keeping every frame. void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (platform side) float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. From cfcad42b89a2a8d8e789c10fd186b753a13bfc02 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 18:22:31 +0100 Subject: [PATCH 064/195] Viewport: Win32: Workaround to the fact that ::WindowFromPoint() seems to return Windows using ImGuiViewportFlags_NoInputs / HTTRANSPARENT when dragging nearby the platform title bar. This is to allow using platform decoration. I don't understand this well atm. (#1542) --- examples/imgui_impl_win32.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index fed43afd..b2134b30 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -185,10 +185,11 @@ static void ImGui_ImplWin32_UpdateMousePos() // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows). // - This is _regardless_ of whether another viewport is focused or being dragged from. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the - // rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows. + // rectangles and last focused time of every viewports it knows about. It will be unaware of foreign windows that may be sitting between or over your windows. if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd)) - io.MouseHoveredViewport = viewport->ID; + if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated? + io.MouseHoveredViewport = viewport->ID; } void ImGui_ImplWin32_NewFrame() From 0d6e3ab2b037a7c789b01eb78e00297c04fc52ca Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 18:56:53 +0100 Subject: [PATCH 065/195] Docking: Renamed SetNextWindowId() -> SetNextWindowID() for consistency. (function vs member are still horribly inconsistent atm) --- imgui.cpp | 4 ++-- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c880763e..84e37289 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6263,7 +6263,7 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) } } -ImGuiID ImGui::GetWindowDockId() +ImGuiID ImGui::GetWindowDockID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DockId; @@ -6524,7 +6524,7 @@ void ImGui::SetNextWindowViewport(ImGuiID id) g.NextWindowData.ViewportId = id; } -void ImGui::SetNextWindowDockId(ImGuiID id, ImGuiCond cond) +void ImGui::SetNextWindowDockID(ImGuiID id, ImGuiCond cond) { ImGuiContext& g = *GImGui; g.NextWindowData.DockCond = cond ? cond : ImGuiCond_Always; diff --git a/imgui.h b/imgui.h index 4873222a..b4745319 100644 --- a/imgui.h +++ b/imgui.h @@ -580,9 +580,9 @@ namespace ImGui // Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details. IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags dockspace_flags = 0, const ImGuiWindowClass* window_class = NULL); - IMGUI_API void SetNextWindowDockId(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) + IMGUI_API void SetNextWindowDockID(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class / user type (docking filters by same user_type) - IMGUI_API ImGuiID GetWindowDockId(); + IMGUI_API ImGuiID GetWindowDockID(); IMGUI_API bool IsWindowDocked(); // is current window docked into another window? // Logging/Capture diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 317e59dc..acd557d6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4275,7 +4275,7 @@ void ShowExampleAppDocuments(bool* p_open) // FIXME-DOCK: SetNextWindowDock() //ImGuiID default_dock_id = GetDockspaceRootDocumentDockID(); //ImGuiID default_dock_id = GetDockspacePreferedDocumentDockID(); - ImGui::SetNextWindowDockId(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver); + ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver); ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0); bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags); From 0cabe4dedfb5a8784ffac3e8f974a63fd0fd8dd3 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 19:29:33 +0100 Subject: [PATCH 066/195] Viewport: Added ImGuiWindowClass / SetNextWindowClass() (concept imported from Docking ImGuiDockFamily), which currently allows to overwrite viewport flags on a per-window basis. Exposed FindViewportByID(). Win32: Support for ParentViewportId. (#1542) --- examples/imgui_impl_win32.cpp | 5 ++++- imgui.cpp | 20 ++++++++++++++++---- imgui.h | 18 +++++++++++++++++- imgui_internal.h | 4 +++- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index b2134b30..9d290fd0 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -454,8 +454,11 @@ static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) viewport->PlatformUserData = data; // Select style and parent window - HWND parent_window = g_hWnd; ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &data->DwStyle, &data->DwExStyle); + HWND parent_window = NULL; + if (viewport->ParentViewportId != 0) + if (ImGuiViewport* parent_viewport = ImGui::FindViewportByID(viewport->ParentViewportId)) + parent_window = (HWND)parent_viewport->PlatformHandle; // Create window RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; diff --git a/imgui.cpp b/imgui.cpp index 681d8210..0902ea3b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4982,6 +4982,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); } + window->WindowClass = g.NextWindowData.WindowClass; if (g.NextWindowData.CollapsedCond) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.FocusCond) @@ -5180,6 +5181,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) viewport_flags |= ImGuiViewportFlags_NoDecoration; + // We can overwrite viewport flags using ImGuiWindowClass (advanced users) + window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId ? window->WindowClass.ParentViewportId : IMGUI_VIEWPORT_DEFAULT_ID; + if (window->WindowClass.ViewportFlagsOverrideMask) + viewport_flags = (viewport_flags & ~window->WindowClass.ViewportFlagsOverrideMask) | (window->WindowClass.ViewportFlagsOverrideValue & window->WindowClass.ViewportFlagsOverrideMask); + // We also tell the back-end that clearing the platform window won't be necessary, as our window is filling the viewport and we have disabled BgAlpha viewport_flags |= ImGuiViewportFlags_NoRendererClear; window->Viewport->Flags = viewport_flags; @@ -6343,6 +6349,12 @@ void ImGui::SetNextWindowViewport(ImGuiID id) g.NextWindowData.ViewportId = id; } +void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.WindowClass = *window_class; +} + // In window space (not screen space!) ImVec2 ImGui::GetContentRegionMax() { @@ -7253,7 +7265,7 @@ ImGuiViewport* ImGui::GetMainViewport() return g.Viewports[0]; } -ImGuiViewportP* ImGui::FindViewportByID(ImGuiID id) +ImGuiViewport* ImGui::FindViewportByID(ImGuiID id) { ImGuiContext& g = *GImGui; for (int n = 0; n < g.Viewports.Size; n++) @@ -7493,7 +7505,7 @@ static void ImGui::UpdateViewportsNewFrame() ImGuiViewportP* viewport_hovered = NULL; if (g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) { - viewport_hovered = g.IO.MouseHoveredViewport ? FindViewportByID(g.IO.MouseHoveredViewport) : NULL; + viewport_hovered = g.IO.MouseHoveredViewport ? (ImGuiViewportP*)FindViewportByID(g.IO.MouseHoveredViewport) : NULL; if (viewport_hovered && (viewport_hovered->Flags & ImGuiViewportFlags_NoInputs)) { // Back-end failed at honoring its contract if it returned a viewport with the _NoInputs flag. @@ -7646,7 +7658,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) // Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file if (window->Viewport == NULL && window->ViewportId != 0) { - window->Viewport = FindViewportByID(window->ViewportId); + window->Viewport = (ImGuiViewportP*)FindViewportByID(window->ViewportId); if (window->Viewport == NULL && window->ViewportPos.x != FLT_MAX && window->ViewportPos.y != FLT_MAX) window->Viewport = AddUpdateViewport(window, window->ID, window->ViewportPos, window->Size, ImGuiViewportFlags_None); } @@ -7655,7 +7667,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) if (g.NextWindowData.ViewportCond) { // Code explicitly request a viewport - window->Viewport = FindViewportByID(g.NextWindowData.ViewportId); + window->Viewport = (ImGuiViewportP*)FindViewportByID(g.NextWindowData.ViewportId); window->ViewportId = g.NextWindowData.ViewportId; // Store ID even if Viewport isn't resolved yet. } else if ((flags & ImGuiWindowFlags_ChildWindow) || (flags & ImGuiWindowFlags_ChildMenu)) diff --git a/imgui.h b/imgui.h index 6d7f8dd2..8154df6e 100644 --- a/imgui.h +++ b/imgui.h @@ -114,6 +114,7 @@ struct ImGuiStyle; // Runtime data for styling/colors struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]") struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) struct ImGuiViewport; // Viewport (generally ~1 per window to output to at the OS level. Need per-platform support to use multiple viewports) +struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform back-end via altered viewport flags and parent/child info) // Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. @@ -276,6 +277,7 @@ namespace ImGui IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id); // set next window viewport + IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class (rare/advanced uses: provide hints to the platform back-end via altered viewport flags and parent/child info) IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). @@ -688,6 +690,7 @@ namespace ImGui IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport. IMGUI_API void RenderPlatformWindowsDefault(void* platform_arg = NULL, void* renderer_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport. may be reimplemented by user for custom rendering needs. IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from back-end Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext(). + IMGUI_API ImGuiViewport* FindViewportByID(ImGuiID id); // this is a helper for back-ends. IMGUI_API ImGuiViewport* FindViewportByPlatformHandle(void* platform_handle); // this is a helper for back-ends. the type platform_handle is decided by the back-end (e.g. HWND, MyWindow*, GLFWwindow* etc.) } // namespace ImGui @@ -1430,6 +1433,18 @@ struct ImGuiPayload bool IsDelivery() const { return Delivery; } }; +// [BETA] Rarely used / very advanced uses only. Use with SetNextWindowClass() function. +// Provide hints to the platform back-end via altered viewport flags (enable/disable OS decoration, OS task bar icons, etc.) and OS level parent/child relationships. +struct ImGuiWindowClass +{ + ImGuiID ClassId; // User data. 0 = Default class (unclassed) + ImGuiID ParentViewportId; // Hint for the platform back-end. If non-zero, the platform back-end can create a parent<>child relationship between the platform windows. Not conforming back-ends are free to e.g. parent every viewport to the main viewport or not. + ImGuiViewportFlags ViewportFlagsOverrideMask; // Viewport flags to override when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. + ImGuiViewportFlags ViewportFlagsOverrideValue; // Viewport flags values to override when a window of this class owns a viewport. + + ImGuiWindowClass() { ClassId = 0; ParentViewportId = 0; ViewportFlagsOverrideMask = ViewportFlagsOverrideValue = 0x00; } +}; + //----------------------------------------------------------------------------- // Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) //----------------------------------------------------------------------------- @@ -2235,6 +2250,7 @@ struct ImGuiViewport ImVec2 Size; // Size of viewport in pixel float DpiScale; // 1.0f = 96 DPI = No extra scale ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame(). + ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform back-end to setup a parent/child relationship between platform windows. void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, frame-buffers etc.) void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context) @@ -2243,7 +2259,7 @@ struct ImGuiViewport bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position) bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size) - ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; RendererUserData = PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } + ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; ParentViewportId = 0; RendererUserData = PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); } }; diff --git a/imgui_internal.h b/imgui_internal.h index fee712b9..16f5dae1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,6 +714,7 @@ struct ImGuiNextWindowData void* SizeCallbackUserData; float BgAlphaVal; ImGuiID ViewportId; + ImGuiWindowClass WindowClass; ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. ImGuiNextWindowData() @@ -733,6 +734,7 @@ struct ImGuiNextWindowData void Clear() { PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = 0; + WindowClass = ImGuiWindowClass(); } }; @@ -1121,6 +1123,7 @@ struct IMGUI_API ImGuiWindow char* Name; ImGuiID ID; // == ImHash(Name) ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_ + ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass() ImGuiViewportP* Viewport; // Always set in Begin(), only inactive windows may have a NULL value here ImGuiID ViewportId; // We backup the viewport id (since the viewport may disappear or never be created if the window is inactive) ImVec2 ViewportPos; // We backup the viewport position (since the viewport may disappear or never be created if the window is inactive) @@ -1331,7 +1334,6 @@ namespace ImGui IMGUI_API void UpdateMouseMovingWindow(); // Viewports - IMGUI_API ImGuiViewportP* FindViewportByID(ImGuiID id); IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport); IMGUI_API void ShowViewportThumbnails(); From 5aebfedfadcfb071b8c7ecf164e0422d6adc949a Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 21:41:00 +0100 Subject: [PATCH 067/195] Docking: Forward WindowClass from node to host window. --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index af0f2fa6..fc561fc7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10952,6 +10952,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) } if (node->InitFromFirstWindowViewport && node->Windows.Size > 0) SetNextWindowViewport(node->Windows[0]->ViewportId); + SetNextWindowClass(&node->WindowClass); // Begin into the host window char window_label[20]; From 1b0e38df47e7b29932717e695e4a76e0bcbec55b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 22:14:28 +0100 Subject: [PATCH 068/195] Fixes crash/assert bug introduced in d845135 (#1651): would assert when showing the CTRL+Tab list and or fallback "...." tooltip. --- imgui.cpp | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 82fcb9af..4d9adb2b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3580,9 +3580,6 @@ void ImGui::EndFrame() return; IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); - g.FrameScopeActive = false; - g.FrameCountEnded = g.FrameCount; - // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) { @@ -3590,6 +3587,31 @@ void ImGui::EndFrame() g.PlatformImeLastPos = g.PlatformImePos; } + // Show CTRL+TAB list window + if (g.NavWindowingTarget) + NavUpdateWindowingList(); + + // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) + if (g.DragDropActive) + { + bool is_delivered = g.DragDropPayload.Delivery; + bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); + if (is_delivered || is_elapsed) + ClearDragDrop(); + } + + // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) + { + g.DragDropWithinSourceOrTarget = true; + SetTooltip("..."); + g.DragDropWithinSourceOrTarget = false; + } + + // End the frame scope. From this point we are not allowed to call Begin() any more. + g.FrameScopeActive = false; + g.FrameCountEnded = g.FrameCount; + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). if (g.CurrentWindowStack.Size != 1) @@ -3611,27 +3633,6 @@ void ImGui::EndFrame() g.CurrentWindow->Active = false; End(); - // Show CTRL+TAB list - if (g.NavWindowingTarget) - NavUpdateWindowingList(); - - // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) - if (g.DragDropActive) - { - bool is_delivered = g.DragDropPayload.Delivery; - bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); - if (is_delivered || is_elapsed) - ClearDragDrop(); - } - - // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. - if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) - { - g.DragDropWithinSourceOrTarget = true; - SetTooltip("..."); - g.DragDropWithinSourceOrTarget = false; - } - // Initiate moving window if (g.ActiveId == 0 && g.HoveredId == 0) { From 3e30bfd6c9750588dbd0a0f904c3ed02c14c4c12 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 22:56:17 +0100 Subject: [PATCH 069/195] Revert "Fixes crash/assert bug introduced in d845135 (#1651): would assert when showing the CTRL+Tab list and or fallback "...." tooltip." This reverts commit 1b0e38df47e7b29932717e695e4a76e0bcbec55b. --- imgui.cpp | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4d9adb2b..82fcb9af 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3580,6 +3580,9 @@ void ImGui::EndFrame() return; IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); + g.FrameScopeActive = false; + g.FrameCountEnded = g.FrameCount; + // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) { @@ -3587,31 +3590,6 @@ void ImGui::EndFrame() g.PlatformImeLastPos = g.PlatformImePos; } - // Show CTRL+TAB list window - if (g.NavWindowingTarget) - NavUpdateWindowingList(); - - // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) - if (g.DragDropActive) - { - bool is_delivered = g.DragDropPayload.Delivery; - bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); - if (is_delivered || is_elapsed) - ClearDragDrop(); - } - - // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. - if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) - { - g.DragDropWithinSourceOrTarget = true; - SetTooltip("..."); - g.DragDropWithinSourceOrTarget = false; - } - - // End the frame scope. From this point we are not allowed to call Begin() any more. - g.FrameScopeActive = false; - g.FrameCountEnded = g.FrameCount; - // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). if (g.CurrentWindowStack.Size != 1) @@ -3633,6 +3611,27 @@ void ImGui::EndFrame() g.CurrentWindow->Active = false; End(); + // Show CTRL+TAB list + if (g.NavWindowingTarget) + NavUpdateWindowingList(); + + // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) + if (g.DragDropActive) + { + bool is_delivered = g.DragDropPayload.Delivery; + bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); + if (is_delivered || is_elapsed) + ClearDragDrop(); + } + + // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount) + { + g.DragDropWithinSourceOrTarget = true; + SetTooltip("..."); + g.DragDropWithinSourceOrTarget = false; + } + // Initiate moving window if (g.ActiveId == 0 && g.HoveredId == 0) { From b3469fa94b79ad56e978130cd28f863f1cbe7217 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 22:52:09 +0100 Subject: [PATCH 070/195] Alternative fix for bug introduced in d845135 (#1651), fix CTRL+Tab and fallback tooltip. --- imgui.cpp | 14 +++++++++----- imgui_internal.h | 5 +++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 82fcb9af..25955ab3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3349,6 +3349,7 @@ void ImGui::NewFrame() // This fallback is particularly important as it avoid ImGui:: calls from crashing. SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); Begin("Debug##Default"); + g.FrameScopePushedImplicitWindow = true; #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_PostNewFrame(); @@ -3580,9 +3581,6 @@ void ImGui::EndFrame() return; IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); - g.FrameScopeActive = false; - g.FrameCountEnded = g.FrameCount; - // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) { @@ -3607,11 +3605,12 @@ void ImGui::EndFrame() } // Hide implicit/fallback "Debug" window if it hasn't been used + g.FrameScopePushedImplicitWindow = false; if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) g.CurrentWindow->Active = false; End(); - // Show CTRL+TAB list + // Show CTRL+TAB list window if (g.NavWindowingTarget) NavUpdateWindowingList(); @@ -3632,6 +3631,10 @@ void ImGui::EndFrame() g.DragDropWithinSourceOrTarget = false; } + // End frame + g.FrameScopeActive = false; + g.FrameCountEnded = g.FrameCount; + // Initiate moving window if (g.ActiveId == 0 && g.HoveredId == 0) { @@ -5283,11 +5286,12 @@ void ImGui::End() { ImGuiContext& g = *GImGui; - if (g.CurrentWindowStack.Size <= 1 && g.FrameScopeActive) + if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow) { IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!"); return; // FIXME-ERRORHANDLING } + IM_ASSERT(g.CurrentWindowStack.Size > 0); ImGuiWindow* window = g.CurrentWindow; diff --git a/imgui_internal.h b/imgui_internal.h index 60704564..d4d6f940 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -694,7 +694,8 @@ struct ImGuiTabBarSortItem struct ImGuiContext { bool Initialized; - bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame()/Render() + bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame() + bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame() bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; ImGuiStyle Style; @@ -859,7 +860,7 @@ struct ImGuiContext ImGuiContext(ImFontAtlas* shared_font_atlas) : OverlayDrawList(NULL) { Initialized = false; - FrameScopeActive = false; + FrameScopeActive = FrameScopePushedImplicitWindow = false; Font = NULL; FontSize = FontBaseSize = 0.0f; FontAtlasOwnedByContext = shared_font_atlas ? false : true; From 237109caa57bd1e34e339f07c0c72f07c0034129 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 23:05:59 +0100 Subject: [PATCH 071/195] Internals: Extracted code out of EndFrame() into UpdateMouseMovingWindowEndFrame() --- imgui.cpp | 99 ++++++++++++++++++++++++++---------------------- imgui_internal.h | 3 +- 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 25955ab3..ec4788a1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2969,7 +2969,7 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) // Handle mouse moving window // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() -void ImGui::UpdateMouseMovingWindow() +void ImGui::UpdateMouseMovingWindowNewFrame() { ImGuiContext& g = *GImGui; if (g.MovingWindow != NULL) @@ -3007,6 +3007,56 @@ void ImGui::UpdateMouseMovingWindow() } } +// Initiate moving window, handle left-click and right-click focus +void ImGui::UpdateMouseMovingWindowEndFrame() +{ + // Initiate moving window + ImGuiContext& g = *GImGui; + if (g.ActiveId != 0 || g.HoveredId != 0) + return; + + // Unless we just made a window/popup appear + if (g.NavWindow && g.NavWindow->Appearing) + return; + + // Click to focus window and start moving (after we're done with all our widgets) + if (g.IO.MouseClicked[0]) + { + if (g.HoveredRootWindow != NULL) + { + StartMouseMovingWindow(g.HoveredWindow); + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + } + else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) + { + FocusWindow(NULL); // Clicking on void disable focus + } + } + + // With right mouse button we close popups without changing focus + // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger) + if (g.IO.MouseClicked[1]) + { + // Find the top-most window between HoveredWindow and the front most Modal Window. + // This is where we can trim the popup stack. + ImGuiWindow* modal = GetFrontMostPopupModal(); + bool hovered_window_above_modal = false; + if (modal == NULL) + hovered_window_above_modal = true; + for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (window == modal) + break; + if (window == g.HoveredWindow) + hovered_window_above_modal = true; + } + ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal); + } +} + static bool IsWindowActiveAndVisible(ImGuiWindow* window) { return (window->Active) && (!window->Hidden); @@ -3298,7 +3348,7 @@ void ImGui::NewFrame() g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) - UpdateMouseMovingWindow(); + UpdateMouseMovingWindowNewFrame(); UpdateHoveredWindowAndCaptureFlags(); // Background darkening/whitening @@ -3635,49 +3685,8 @@ void ImGui::EndFrame() g.FrameScopeActive = false; g.FrameCountEnded = g.FrameCount; - // Initiate moving window - if (g.ActiveId == 0 && g.HoveredId == 0) - { - if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear - { - // Click to focus window and start moving (after we're done with all our widgets) - if (g.IO.MouseClicked[0]) - { - if (g.HoveredRootWindow != NULL) - { - StartMouseMovingWindow(g.HoveredWindow); - if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar)) - if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) - g.MovingWindow = NULL; - } - else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) - { - FocusWindow(NULL); // Clicking on void disable focus - } - } - - // With right mouse button we close popups without changing focus - // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger) - if (g.IO.MouseClicked[1]) - { - // Find the top-most window between HoveredWindow and the front most Modal Window. - // This is where we can trim the popup stack. - ImGuiWindow* modal = GetFrontMostPopupModal(); - bool hovered_window_above_modal = false; - if (modal == NULL) - hovered_window_above_modal = true; - for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) - { - ImGuiWindow* window = g.Windows[i]; - if (window == modal) - break; - if (window == g.HoveredWindow) - hovered_window_above_modal = true; - } - ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal); - } - } - } + // Initiate moving window + handle left-click and right-click focus + UpdateMouseMovingWindowEndFrame(); // Sort the window list so that all child windows are after their parent // We cannot do that on FocusWindow() because childs may not exist yet diff --git a/imgui_internal.h b/imgui_internal.h index d4d6f940..3a25c3c9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1261,7 +1261,8 @@ namespace ImGui // NewFrame IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); - IMGUI_API void UpdateMouseMovingWindow(); + IMGUI_API void UpdateMouseMovingWindowNewFrame(); + IMGUI_API void UpdateMouseMovingWindowEndFrame(); // Settings IMGUI_API void MarkIniSettingsDirty(); From c3efccaa9ca798bc545dc93b8e79972dcb382bfd Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 23:49:31 +0100 Subject: [PATCH 072/195] Docking: Merge fix duplicate line + added assert to ease debugging. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index e697ceab..a37cc8fc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3513,7 +3513,6 @@ void ImGui::NewFrame() // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) UpdateMouseMovingWindowNewFrame(); - UpdateHoveredWindowAndCaptureFlags(); // Background darkening/whitening if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) @@ -10316,6 +10315,7 @@ void ImGui::DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id void ImGui::DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer) { + IM_ASSERT(target != payload); ImGuiDockRequest req; req.Type = ImGuiDockRequestType_Dock; req.DockTargetWindow = target; From 64c66529ae7d85db59e00f0692b0705255d1a163 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 13:35:53 +0100 Subject: [PATCH 073/195] Moving issue/pr template to docs/. Added links in README. --- .github/CONTRIBUTING.md | 1 - .github/pull_request_template.md | 12 ------------ docs/README.md | 6 +++--- {.github => docs}/issue_template.md | 0 docs/pull_request_template.md | 6 ++++++ 5 files changed, 9 insertions(+), 16 deletions(-) delete mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/pull_request_template.md rename {.github => docs}/issue_template.md (100%) create mode 100644 docs/pull_request_template.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 84a39d29..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -Please read https://github.com/ocornut/imgui/issues/2261 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index ad66ea6f..00000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,12 +0,0 @@ -(Click "Preview" to turn any http URL into a clickable link) - -1. PLEASE CAREFULLY READ: -https://github.com/ocornut/imgui/issues/2261 - -2. PLEASE MAKE SURE YOU HAVE READ: -https://github.com/ocornut/imgui/issues/2261 - -3. DID I MENTION YOU SHOULD READ THIS? -https://github.com/ocornut/imgui/issues/2261 - -(Clear this form before submitting your PR) diff --git a/docs/README.md b/docs/README.md index 809f19f8..0efd2dff 100644 --- a/docs/README.md +++ b/docs/README.md @@ -205,7 +205,7 @@ See the [Wiki](https://github.com/ocornut/imgui/wiki) for more references and [B Support Forums -------------- -If you have issues with: compiling, linking, adding fonts, running or displaying Dear ImGui, or wiring inputs: please post on the Discourse forum: https://discourse.dearimgui.org. +If you have issues with: compiling, linking, adding fonts, running or displaying Dear ImGui, or wiring inputs: please post on the Discourse forums: https://discourse.dearimgui.org. For any other questions, bug reports, requests, feedback, you may post on https://github.com/ocornut/imgui/issues. Please read and fill the New Issue template carefully. @@ -273,9 +273,9 @@ Support dear imgui **How can I help?** -- You may participate in the Discourse and GitHub [issues trackers](https://github.com/ocornut/imgui/issues). +- You may participate in the [Discourse forums](https://discourse.dearimgui.org) and the GitHub [issues tracker](https://github.com/ocornut/imgui/issues). - You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. -- See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the Wiki for some more ideas. +- See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas. - Convince your company to financially support this project. **How can I help financing further development of Dear ImGui?** diff --git a/.github/issue_template.md b/docs/issue_template.md similarity index 100% rename from .github/issue_template.md rename to docs/issue_template.md diff --git a/docs/pull_request_template.md b/docs/pull_request_template.md new file mode 100644 index 00000000..533027c9 --- /dev/null +++ b/docs/pull_request_template.md @@ -0,0 +1,6 @@ +(Click "Preview" to turn any http URL into a clickable link) + +PLEASE CAREFULLY READ: +https://github.com/ocornut/imgui/issues/2261 + +(Clear this template before submitting your PR) From 25ac85f15daca70d8327234fc83228f3e2075f26 Mon Sep 17 00:00:00 2001 From: Alzathar Date: Thu, 3 Jan 2019 08:01:14 -0500 Subject: [PATCH 074/195] Examples: Downgrading projects to xcode 9.2 (maybe 8.0) (#2134) * example_apple_opengl2: The deployment target was set to 10.12 from XCode 9.2. * imgui_impl_metal: header not found by XCode 9.2. * example_apple_metal: The deployment target was set to 10.12 from XCode 9.2. --- .../project.pbxproj | 28 ++++++------------- .../project.pbxproj | 5 +++- examples/imgui_impl_metal.mm | 2 +- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj index 71eca965..f1c10494 100644 --- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj +++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj @@ -231,14 +231,16 @@ TargetAttributes = { 8307E7C320E9F9C900473790 = { CreatedOnToolsVersion = 9.4.1; + ProvisioningStyle = Automatic; }; 8307E7D920E9F9C900473790 = { CreatedOnToolsVersion = 9.4.1; + ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 8307E7B920E9F9C700473790 /* Build configuration list for PBXProject "example_apple_metal" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -444,10 +446,7 @@ DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios"; PRODUCT_NAME = example_apple_metal; SDKROOT = iphoneos; @@ -463,10 +462,7 @@ DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios"; PRODUCT_NAME = example_apple_metal; SDKROOT = iphoneos; @@ -483,11 +479,8 @@ COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos"; PRODUCT_NAME = example_apple_metal; SDKROOT = macosx; @@ -502,11 +495,8 @@ COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos"; PRODUCT_NAME = example_apple_metal; SDKROOT = macosx; diff --git a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj index 514c6808..20504102 100644 --- a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj +++ b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj @@ -135,11 +135,12 @@ TargetAttributes = { 4080A96A20B029B00036BA46 = { CreatedOnToolsVersion = 9.3.1; + ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 4080A96620B029B00036BA46 /* Build configuration list for PBXProject "example_apple_opengl2" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -286,6 +287,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_NAME = "$(TARGET_NAME)"; SYSTEM_HEADER_SEARCH_PATHS = ../libs/gl3w; USER_HEADER_SEARCH_PATHS = ../..; @@ -296,6 +298,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_NAME = "$(TARGET_NAME)"; SYSTEM_HEADER_SEARCH_PATHS = ../libs/gl3w; USER_HEADER_SEARCH_PATHS = ../..; diff --git a/examples/imgui_impl_metal.mm b/examples/imgui_impl_metal.mm index ae960e9f..562a01b9 100644 --- a/examples/imgui_impl_metal.mm +++ b/examples/imgui_impl_metal.mm @@ -17,7 +17,7 @@ #include "imgui_impl_metal.h" #import -#import +// #import // Not suported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...) #import #pragma mark - Support classes From 599a52629a19ff7fdf313a81e2f80871750eec55 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 17:43:15 +0100 Subject: [PATCH 075/195] Viewport: Added minimum viable information in the Changelog. --- docs/CHANGELOG.txt | 41 +++++++++++++++++++++++++++++++++++++++++ imgui.cpp | 6 ++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5372446..8e427fb4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -29,6 +29,46 @@ HOW TO UPDATE? - Please report any issue! +----------------------------------------------------------------------- + VIEWPORT BRANCH (In Progress) +----------------------------------------------------------------------- + +Breaking Changes: + +- IMPORTANT: When multi-viewports are enabled (with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable), + all coordinates/positions will be in your natural OS coordinates space. It means that: + - Reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are _probably_ not what you want anymore. + Use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos). + - Likewise io.MousePos and GetMousePos() will use OS coordinates. + If you query mouse positions to interact with non-imgui coordinates you will need to offset them. + e.g. subtract GetWindowViewport()->Pos. +- IO: Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. +- IO: Removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were marked obsoleted, used to clip within the (0,0)..(DisplaySize) range). + + +Other changes: +(FIXME: This need a fuller explanation!) + +- Added ImGuiPlatformIO structure and GetPlatformIO(). + Similarly to ImGuiIO and GetIO(), this structure is the main point of communication for back-ends supporting multi-viewports. +- Added ImGuiPlatformMonitor to feed OS monitor information in the ImGuiPlatformIO::Monitors. +- Added GetMainViewport(). +- Added GetWindowViewport(), SetNextWindowViewport(). +- Added GetWindowDpiScale(). +- Added GetOverlayDrawList(ImGuiViewport* viewport). + The no-parameter version of GetOverlayDrawList() return the overlay for the current window's viewport. +- Added UpdatePlatformWindows(), RenderPlatformWindows(), DestroyPlatformWindows() for usage for application core. +- Added FindViewportByID(), FindViewportByPlatformHandle() for usage by back-ends. +- Added ImGuiConfigFlags_ViewportsEnable configuration flag and other viewport options. +- Added ImGuiBackendFlags_PlatformHasViewports, ImGuiBackendFlags_RendererHasViewports, ImGuiBackendFlags_HasMouseHoveredViewport backend flags. +- Added io.MainViewport, io.Viewports, io.MouseHoveredViewport (MouseHoveredViewport is optional _even_ for multi-viewport support). +- Added ImGuiViewport structure, ImGuiViewportFlags flags. +- Added ImGuiWindowClass and SetNextWindowClass() for passing viewport related hints to the OS/platform back-end. +- Examples: Renderer: OpenGL2, OpenGL3, DirectX11, DirectX12, Vulkan: Added support for multi-viewports. +- Examples: Platforms: Win32, GLFW, SDL2: Added support for multi-viewports. + Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117. + + ----------------------------------------------------------------------- VERSION 1.67 (In Progress) ----------------------------------------------------------------------- @@ -41,6 +81,7 @@ Breaking Changes: undesirable side-effect as the window would have ID zero. In particular it is causing problems in viewport/docking branches. Other Changes: + - Added BETA api for Tab Bar/Tabs widgets: (#261, #351) - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. - Added ImGuiTabBarFlags flags for BeginTabBar(). diff --git a/imgui.cpp b/imgui.cpp index 310a55fd..763d58d2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -365,15 +365,13 @@ CODE You can read releases logs https://github.com/ocornut/imgui/releases for more details. (Viewport Branch) - - 2018/XX/XX (1.XX) - examples: the examples imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.) - when adopting new bindings follow the code in examples/ to know which functions to call. - 2018/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that: - reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore. you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos) - - likewise io.MousePos and GetMousePos() will use OS coordinates coordinates. + - likewise io.MousePos and GetMousePos() will use OS coordinates. If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos. - 2018/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. - - 2018/XX/XX (1.XX) - removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (it was used to clip within the DisplayMin..DisplayMax range, I don't know of anyone using it) + - 2018/XX/XX (1.XX) - removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were used to clip within the (0,0)..DisplaySize range, I don't know of anyone using it) - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. From ca6ac34f9dd874c000bcbaa23b8a33fa5eb1e432 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 18:38:20 +0100 Subject: [PATCH 076/195] Natvis: Added Hidden info about ImGuiWindow. --- misc/natvis/imgui.natvis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/natvis/imgui.natvis b/misc/natvis/imgui.natvis index 48b20426..cc768bfb 100644 --- a/misc/natvis/imgui.natvis +++ b/misc/natvis/imgui.natvis @@ -33,7 +33,7 @@ - {{Name={Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d}} + {{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}} \ No newline at end of file From 05bc323be0aaf31704a7f959160f73b64abef284 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 20:16:40 +0100 Subject: [PATCH 077/195] Viewport: Fixed minimization of main viewport leading to it being omitted from platform_io.Viewport list where the users assume it is at index 0. Fix d8ab2c1ac. It wasn't a problem when other viewports were child of the main viewport because they would all be minimized together. (#1542) --- imgui.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 763d58d2..cae05b0e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7419,7 +7419,6 @@ static void ImGui::UpdateViewportsNewFrame() ImGuiContext& g = *GImGui; IM_ASSERT(g.PlatformIO.Viewports.Size <= g.Viewports.Size); - // Update main viewport with current platform position and size ImGuiViewportP* main_viewport = g.Viewports[0]; IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID); IM_ASSERT(main_viewport->Window == NULL); @@ -7461,9 +7460,6 @@ static void ImGui::UpdateViewportsNewFrame() const bool platform_funcs_available = (n == 0 || viewport->PlatformWindowCreated); if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) { - if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available) - viewport->PlatformWindowMinimized = g.PlatformIO.Platform_GetWindowMinimized(viewport); - // Update Position and Size (from Platform Window to ImGui) if requested. // We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities. if (!viewport->PlatformWindowMinimized && platform_funcs_available) @@ -7577,7 +7573,8 @@ static void ImGui::UpdateViewportsEndFrame() ImGuiViewportP* viewport = g.Viewports[i]; viewport->LastPos = viewport->Pos; if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) - continue; + if (i > 0) // Always include main viewport in the list + continue; if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)) continue; if (i > 0) From 606175b98fd1e444e35f901473558d87dfbe7b5b Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 20:43:28 +0100 Subject: [PATCH 078/195] Viewport: Fix for minimization of individual viewports (the current back-end forcing a parent/child relationship between secondary viewports and the main viewport have hidden this issue). Follows d8ab2c1ac. --- imgui.cpp | 20 ++++++++++++++++---- imgui_internal.h | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cae05b0e..e65a74ec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5169,7 +5169,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) window->Pos = FindBestWindowPosForPopup(window); - if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned) + if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned && !window->Viewport->PlatformWindowMinimized) if (!window->Viewport->GetRect().Contains(window->Rect())) { // Late create viewport, based on the assumption that with our calculations, the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport) @@ -7419,13 +7419,25 @@ static void ImGui::UpdateViewportsNewFrame() ImGuiContext& g = *GImGui; IM_ASSERT(g.PlatformIO.Viewports.Size <= g.Viewports.Size); + // Update Minimized status (we need it first in order to decide if we'll apply Pos/Size of the main viewport) + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + const bool platform_funcs_available = (n == 0 || viewport->PlatformWindowCreated); + if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) + if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available) + viewport->PlatformWindowMinimized = g.PlatformIO.Platform_GetWindowMinimized(viewport); + } + + // Create/update main viewport with current platform position and size ImGuiViewportP* main_viewport = g.Viewports[0]; IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID); IM_ASSERT(main_viewport->Window == NULL); ImVec2 main_viewport_platform_pos = ImVec2(0.0f, 0.0f); - if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) - main_viewport_platform_pos = g.PlatformIO.Platform_GetWindowPos(main_viewport); - AddUpdateViewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, main_viewport_platform_pos, g.IO.DisplaySize, ImGuiViewportFlags_CanHostOtherWindows); + ImVec2 main_viewport_platform_size = g.IO.DisplaySize; + if (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable) + main_viewport_platform_pos = main_viewport->PlatformWindowMinimized ? main_viewport->Pos : g.PlatformIO.Platform_GetWindowPos(main_viewport); + AddUpdateViewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, main_viewport_platform_pos, main_viewport_platform_size, ImGuiViewportFlags_CanHostOtherWindows); g.CurrentViewport = NULL; g.MouseViewport = NULL; diff --git a/imgui_internal.h b/imgui_internal.h index 7f7af12a..1df0acf8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -664,7 +664,7 @@ struct ImGuiViewportP : public ImGuiViewport float LastAlpha; short PlatformMonitor; bool PlatformWindowCreated; - bool PlatformWindowMinimized; + bool PlatformWindowMinimized; // When minimized we tend to avoid using the viewport pos/size for clipping window or testing if they are contained in the viewport ImGuiWindow* Window; // Set when the viewport is owned by a window (and ImGuiViewportFlags_CanHostOtherWindows is NOT set) ImDrawList* OverlayDrawList; // For convenience, a draw list we can render to that's always rendered last (we use it to draw software mouse cursor when io.MouseDrawCursor is set) ImDrawData DrawDataP; From c8349d33052e6e65ee2b539f7ad400e4967c7fa4 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 20:47:58 +0100 Subject: [PATCH 079/195] Viewport: Added ConfigViewportsNoParent to parent viewport default to NULL and not main viewport. Fix eg.. popups appearing erroneously focusing parent window. --- imgui.cpp | 10 ++++++++-- imgui.h | 1 + imgui_demo.cpp | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e65a74ec..62923d40 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1145,6 +1145,7 @@ ImGuiIO::ImGuiIO() DisplayFramebufferScale = ImVec2(1.0f, 1.0f); // Miscellaneous configuration options + ConfigViewportsNoParent = false; #ifdef __APPLE__ ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag #else @@ -5201,7 +5202,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) viewport_flags |= ImGuiViewportFlags_NoDecoration; // We can overwrite viewport flags using ImGuiWindowClass (advanced users) - window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId ? window->WindowClass.ParentViewportId : IMGUI_VIEWPORT_DEFAULT_ID; + // We don't default to the main viewport because. + if (window->WindowClass.ParentViewportId) + window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId; + else + window->Viewport->ParentViewportId = g.IO.ConfigViewportsNoParent ? 0 : IMGUI_VIEWPORT_DEFAULT_ID; if (window->WindowClass.ViewportFlagsOverrideMask) viewport_flags = (viewport_flags & ~window->WindowClass.ViewportFlagsOverrideMask) | (window->WindowClass.ViewportFlagsOverrideValue & window->WindowClass.ViewportFlagsOverrideMask); @@ -5476,6 +5481,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->Viewport->PlatformRequestClose = false; g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue. + //IMGUI_DEBUG_LOG("Window '%s' PlatformRequestClose\n", window->Name); *p_open = false; } @@ -10307,7 +10313,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) static void NodeViewport(ImGuiViewportP* viewport) { ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->Window ? viewport->Window->Name : "N/A")) + if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A")) { ImGuiWindowFlags flags = viewport->Flags; ImGui::BulletText("Pos: (%.0f,%.0f), Size: (%.0f,%.0f), Monitor: %d, DpiScale: %.0f%%", viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, viewport->PlatformMonitor, viewport->DpiScale * 100.0f); diff --git a/imgui.h b/imgui.h index 8154df6e..168cca32 100644 --- a/imgui.h +++ b/imgui.h @@ -1266,6 +1266,7 @@ struct ImGuiIO // Miscellaneous configuration options bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. + bool ConfigViewportsNoParent; // = false // By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 664d93f6..5440e40d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -327,6 +327,9 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away)."); ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoMerge", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoMerge); ImGui::SameLine(); ShowHelpMarker("All floating windows will always create their own viewport and platform window."); + ImGui::Checkbox("io.ConfigViewportNoParent", &io.ConfigViewportsNoParent); + ImGui::SameLine(); ShowHelpMarker("By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows."); + ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); From e1ed27aeaa059822641d9828f9ba60d5255f0491 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 21:27:15 +0100 Subject: [PATCH 080/195] (Breaking change) Reorganized Viewports advanced flags, moved into new io.ConfigViewportsXXX flags. Pay attention that ImGuiConfigFlags_ViewportsDecoration became ConfigViewportsNoDecoeration, so the value is inverted! (#1542) --- imgui.cpp | 14 ++++++++++---- imgui.h | 16 +++++++++------- imgui_demo.cpp | 30 +++++++++++++++++++----------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 62923d40..f938cdb3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1144,8 +1144,14 @@ ImGuiIO::ImGuiIO() FontAllowUserScaling = false; DisplayFramebufferScale = ImVec2(1.0f, 1.0f); - // Miscellaneous configuration options + // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) + ConfigViewportsNoAutoMerge = false; + ConfigViewportsNoTaskBarIcon = false; + ConfigViewportsNoDecoration = true; ConfigViewportsNoParent = false; + + // Miscellaneous options + MouseDrawCursor = false; #ifdef __APPLE__ ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag #else @@ -5196,9 +5202,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) ImGuiViewportFlags viewport_flags = (window->Viewport->Flags) & ~(ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration); if (flags & ImGuiWindowFlags_Tooltip) viewport_flags |= ImGuiViewportFlags_TopMost; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) != 0 || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) + if (g.IO.ConfigViewportsNoTaskBarIcon || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) + if (g.IO.ConfigViewportsNoDecoration || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) viewport_flags |= ImGuiViewportFlags_NoDecoration; // We can overwrite viewport flags using ImGuiWindowClass (advanced users) @@ -7348,7 +7354,7 @@ static bool ImGui::GetWindowAlwaysWantOwnViewport(ImGuiWindow* window) { // Tooltips and menus are not automatically forced into their own viewport when the NoMerge flag is set, however the multiplication of viewports makes them more likely to protude and create their own. ImGuiContext& g = *GImGui; - if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoMerge) && (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) + if (g.IO.ConfigViewportsNoAutoMerge && (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) //if (!window->DockIsActive) if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip)) == 0) return true; diff --git a/imgui.h b/imgui.h index 168cca32..3d1eda8a 100644 --- a/imgui.h +++ b/imgui.h @@ -991,11 +991,8 @@ enum ImGuiConfigFlags_ // [BETA] Viewports // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable. ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends) - ImGuiConfigFlags_ViewportsNoTaskBarIcon = 1 << 11, // Disable task bars icons for all secondary viewports (will set ImGuiViewportFlags_NoTaskBarIcon on them) - ImGuiConfigFlags_ViewportsDecoration = 1 << 12, // FIXME [Broken] Enable platform decoration for all secondary viewports (will not set ImGuiViewportFlags_NoDecoration on them). This currently doesn't behave well in Windows because 1) By default the new window animation get in the way of our transitions, 2) It enable a minimum window size which tends to breaks resizing. You can workaround the later by setting style.WindowMinSize to a bigger value. - ImGuiConfigFlags_ViewportsNoMerge = 1 << 13, // All floating windows will always create their own viewport and platform window. - ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 14, // FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). Note that resizing the main window itself is up to your application. - ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 15, // FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress. + ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 14, // [BETA: Don't use] FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). Note that resizing the main window itself is up to your application. + ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 15, // [BETA: Don't use] FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress. // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui) ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. @@ -1264,9 +1261,14 @@ struct ImGuiIO ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For hi-dpi/retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui. - // Miscellaneous configuration options + // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) + bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. + bool ConfigViewportsNoTaskBarIcon; // = false // Set default OS task bar icon enable flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it. + bool ConfigViewportsNoDecoration; // = true // [BETA] Set default OS window decoration enable flags for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size). + bool ConfigViewportsNoParent; // = false // Set default OS parenting for secondary viewports. By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. + + // Miscellaneous options bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. - bool ConfigViewportsNoParent; // = false // By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5440e40d..753a3812 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -320,15 +320,22 @@ void ImGui::ShowDemoWindow(bool* p_open) } ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); + ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable); - ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoTaskBarIcon", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoTaskBarIcon); - ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away)."); - ImGui::CheckboxFlags("io.ConfigFlags: ViewportsDecoration", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsDecoration); - ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away)."); - ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoMerge", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoMerge); - ImGui::SameLine(); ShowHelpMarker("All floating windows will always create their own viewport and platform window."); - ImGui::Checkbox("io.ConfigViewportNoParent", &io.ConfigViewportsNoParent); - ImGui::SameLine(); ShowHelpMarker("By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows."); + ImGui::SameLine(); ShowHelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details."); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGui::Indent(); + ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge); + ImGui::SameLine(); ShowHelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it."); + ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon); + ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away)."); + ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration); + ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away)."); + ImGui::Checkbox("io.ConfigViewportsNoParent", &io.ConfigViewportsNoParent); + ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the parenting right away)."); + ImGui::Unindent(); + } ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); @@ -2669,12 +2676,13 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable"); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) ImGui::Text(" ViewportsNoTaskBarIcon"); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsNoMerge) ImGui::Text(" ViewportsNoMerge"); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) ImGui::Text(" ViewportsDecoration"); if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports"); if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts"); if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); + if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge"); + if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon"); + if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration"); + if (io.ConfigViewportsNoParent) ImGui::Text("io.ConfigViewportsNoParent"); if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); From 67775448556d8dba304657719829f1ab768b3c97 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 21:42:36 +0100 Subject: [PATCH 081/195] Added sanity check to debug parent/child ordering issues (they would generally manifest with an assert/crash in EndFrame bu tthis assert will catch some earlier). --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index ec4788a1..12f1ac25 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4910,6 +4910,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Position child window if (flags & ImGuiWindowFlags_ChildWindow) { + IM_ASSERT(parent_window->Active); window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) From 4e98d4329b1b4d41f37ea4ee0167ac03ce63a259 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 21:59:13 +0100 Subject: [PATCH 082/195] Comments --- imgui.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index ac276f8b..d49dd1e6 100644 --- a/imgui.h +++ b/imgui.h @@ -1305,9 +1305,9 @@ struct ImGuiIO // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. - bool ConfigViewportsNoTaskBarIcon; // = false // Set default OS task bar icon enable flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it. - bool ConfigViewportsNoDecoration; // = true // [BETA] Set default OS window decoration enable flags for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size). - bool ConfigViewportsNoParent; // = false // Set default OS parenting for secondary viewports. By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. + bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it. + bool ConfigViewportsNoDecoration; // = true // [BETA] Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size). + bool ConfigViewportsNoParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. // Miscellaneous options bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. From 7f7e8eeecd4d4726aae20d2238a7c92bc2b4d617 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 22:11:14 +0100 Subject: [PATCH 083/195] Docking: Fixed a bug undocking a window from its tab when it is the only docked window of a root dockspace with ConfigDockingTabBarOnSingleWindows enabled. --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d1fab21..127e1df3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6479,8 +6479,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // FIXME-DOCK: In theory we shouldn't test for the ConfigDockingNodifySingleWindows flag here. // When our single window node and OnlyNodeWithWindows are working properly we may remove this check here. ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL; - const bool single_window_node = node && node->IsRootNode() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; - if (held && single_window_node && IsMouseDragging(0, 0.0f)) + const bool single_floating_window_node = node && node->IsRootNode() && !node->IsDockSpace && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; + if (held && single_floating_window_node && IsMouseDragging(0, 0.0f)) { // Move StartMouseMovingWindow(docked_window); From 515ecbddc270f3129642e9f1ab8d95e3778a0b95 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 Jan 2019 23:02:40 +0100 Subject: [PATCH 084/195] Docking: Fix for handling of orphan/inactive dock node with ConfigDockingTabBarOnSingleWindows (would crash). --- imgui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index dc47c459..fc766205 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5299,6 +5299,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Position child window if (flags & ImGuiWindowFlags_ChildWindow) { + IM_ASSERT(parent_window->Active); window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) @@ -12517,7 +12518,11 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) // Create node if (dock_node == NULL) + { dock_node = DockContextAddNode(ctx, window->DockId); + if (auto_dock_node) + dock_node->LastFrameAlive = g.FrameCount; + } DockNodeAddWindow(dock_node, window, true); IM_ASSERT(dock_node == window->DockNode); @@ -12538,7 +12543,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) // Undock if our dockspace node disappeared // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. - if (dock_node->LastFrameAlive < g.FrameCount && !auto_dock_node) + if (dock_node->LastFrameAlive < g.FrameCount) { // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); From 4483320f0ab1e77fe0969c900bf7f6e30fc2c3fb Mon Sep 17 00:00:00 2001 From: DomRe <8564184+DomRe@users.noreply.github.com> Date: Fri, 4 Jan 2019 20:11:24 +0800 Subject: [PATCH 085/195] Examples: Allegro 5: Properly destroy all globals on shutdown. (#2262) --- docs/CHANGELOG.txt | 1 + examples/imgui_impl_allegro5.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index df5b685b..5af45c63 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,7 @@ Other Changes: - Demo: Added a few more things under "Child windows" (changing ImGuiCol_ChildBg, positioning child, using IsItemHovered after a child). - Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file to ease integration. +- Examples: Allegro 5: Properly destroy globals on shutdown to allow for restart. (#2262) [@DomRe] ----------------------------------------------------------------------- diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp index 004638e8..8d534516 100644 --- a/examples/imgui_impl_allegro5.cpp +++ b/examples/imgui_impl_allegro5.cpp @@ -280,9 +280,14 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) void ImGui_ImplAllegro5_Shutdown() { ImGui_ImplAllegro5_InvalidateDeviceObjects(); + g_Display = NULL; + g_Time = 0.0; + + if (g_VertexDecl) + al_destroy_vertex_decl(g_VertexDecl); + g_VertexDecl = NULL; - // Destroy last known clipboard data if (g_ClipboardTextData) al_free(g_ClipboardTextData); g_ClipboardTextData = NULL; From d223d1e951227e65626879c0d19f93f68bbdccfc Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 Jan 2019 15:27:52 +0100 Subject: [PATCH 086/195] Added bindings in Readme. Added internal IMGUI_DEBUG_LOG() helper. Comments, missing breaking changes note relative to imgui_impl_xxxx changes, not really part of core but worth adding in the imgui.cpp breaking change section. --- docs/README.md | 1 + imgui.cpp | 9 ++++++--- imgui.h | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index 0efd2dff..994dda3f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -127,6 +127,7 @@ Languages: (third-party bindings) - Pascal: [imgui-pas](https://github.com/dpethes/imgui-pas) - PureBasic: [pb-cimgui](https://github.com/hippyau/pb-cimgui) - Python [CyImGui](https://github.com/chromy/cyimgui) or [pyimgui](https://github.com/swistakm/pyimgui) +- Ruby: [ruby-imgui](https://github.com/vaiorabbit/ruby-imgui) - Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs) - Swift [swift-imgui](https://github.com/mnmly/Swift-imgui) diff --git a/imgui.cpp b/imgui.cpp index 12f1ac25..d206a8e4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -379,6 +379,9 @@ CODE - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). + - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). + old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant. + when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. @@ -5378,7 +5381,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId g.NavIdIsAlive = false; g.NavLayer = ImGuiNavLayer_Main; - //printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL); + //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL); } // Passing NULL allow to disable keyboard focus @@ -6555,7 +6558,7 @@ void ImGui::OpenPopupEx(ImGuiID id) popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; - //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id); + //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id); if (g.OpenPopupStack.Size < current_stack_size + 1) { g.OpenPopupStack.push_back(popup_ref); @@ -7345,7 +7348,7 @@ static void ImGui::NavUpdate() ImGuiContext& g = *GImGui; g.IO.WantSetMousePos = false; #if 0 - if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); + if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); #endif // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard) diff --git a/imgui.h b/imgui.h index 08cd8504..bd4b7203 100644 --- a/imgui.h +++ b/imgui.h @@ -640,7 +640,7 @@ namespace ImGui IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down) IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold - IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into diff --git a/imgui_internal.h b/imgui_internal.h index 3a25c3c9..a4edaf85 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -101,6 +101,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe #else #define IM_NEWLINE "\n" #endif +#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 18567602..32d52da5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5847,7 +5847,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG g.CurrentTabBar.push_back(tab_bar); if (tab_bar->CurrFrameVisible == g.FrameCount) { - //printf("[%05d] BeginTabBarEx already called this frame\n", g.FrameCount); + //IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount); IM_ASSERT(0); return true; } From 9ba202821f6d5dddf6caf3ea412c97c9e50271d0 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 Jan 2019 19:03:56 +0100 Subject: [PATCH 087/195] Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary keep the focus on the parent window, which could steal it from newly appearing windows. (#787) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 1 + imgui.h | 2 +- imgui_widgets.cpp | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5af45c63..bfbd0ca7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,8 @@ Other Changes: - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) +- Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary + keep the focus on the parent window, which could steal it from newly appearing windows. (#787) - Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function itself at the call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) - Error recovery: Missing calls to End(), pass the assert, should not lead to crashes or to the fallback Debug window diff --git a/imgui.cpp b/imgui.cpp index d206a8e4..07e26e0c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2533,6 +2533,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) } } +// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring. void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index bd4b7203..8c0a95ac 100644 --- a/imgui.h +++ b/imgui.h @@ -1282,7 +1282,7 @@ struct ImGuiIO bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. - float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame, all values will be cleared back to zero in ImGui::EndFrame) + float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). // Functions IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 32d52da5..7f6b86e8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -488,7 +488,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. g.NavActivateId = id; // This is so SetActiveId assign a Nav source SetActiveID(id, window); - if (!(flags & ImGuiButtonFlags_NoNavFocus)) + if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus)) SetFocusID(id, window); g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); } From 8b5f63562461ebfc0590353800353ef022ff488d Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 6 Jan 2019 14:43:43 +0100 Subject: [PATCH 088/195] Added alternative Rust bindings --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 994dda3f..c40aaf54 100644 --- a/docs/README.md +++ b/docs/README.md @@ -128,7 +128,7 @@ Languages: (third-party bindings) - PureBasic: [pb-cimgui](https://github.com/hippyau/pb-cimgui) - Python [CyImGui](https://github.com/chromy/cyimgui) or [pyimgui](https://github.com/swistakm/pyimgui) - Ruby: [ruby-imgui](https://github.com/vaiorabbit/ruby-imgui) -- Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs) +- Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs) or [imgui-rust](https://github.com/nsf/imgui-rust) - Swift [swift-imgui](https://github.com/mnmly/Swift-imgui) Frameworks: From 1705a81efb9a718c5bdefc842fb7e4d40e1e3099 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 Jan 2019 19:18:19 +0100 Subject: [PATCH 089/195] Moved ImVector higher up in imgui :( because we will need it in ImGuiIO. --- imgui.h | 139 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/imgui.h b/imgui.h index 8c0a95ac..eaf2c640 100644 --- a/imgui.h +++ b/imgui.h @@ -13,11 +13,12 @@ Index of this file: // Forward declarations and basic types // ImGui API (Dear ImGui end-user API) // Flags & Enumerations +// ImVector // ImGuiStyle // ImGuiIO // Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) // Obsolete functions -// Helpers (ImVector, ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) +// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) // Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont) @@ -1148,6 +1149,77 @@ enum ImGuiCond_ #endif }; +//----------------------------------------------------------------------------- +// Helper: ImVector<> +// Lightweight std::vector<>-like class to avoid dragging dependencies (also: some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. +// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// do NOT use this class as a std::vector replacement in your own code! +//----------------------------------------------------------------------------- + +template +class ImVector +{ +public: + int Size; + int Capacity; + T* Data; + + typedef T value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ~ImVector() { if (Data) ImGui::MemFree(Data); } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; } + + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int capacity() const { return Capacity; } + inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } + inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } + + inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } + inline iterator begin() { return Data; } + inline const_iterator begin() const { return Data; } + inline iterator end() { return Data + Size; } + inline const_iterator end() const { return Data + Size; } + inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size,const value_type& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline void reserve(int new_capacity) + { + if (new_capacity <= Capacity) + return; + value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); + if (Data) + { + memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); + ImGui::MemFree(Data); + } + Data = new_data; + Capacity = new_capacity; + } + + // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. + inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } + inline iterator erase(const_iterator it, const_iterator it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(value_type)); Size -= (int)count; return Data + off; } + inline iterator erase_unsorted(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(value_type)); Size--; return Data + off; } + inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline int index_from_pointer(const_iterator it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } +}; + //----------------------------------------------------------------------------- // ImGuiStyle // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). @@ -1447,71 +1519,6 @@ typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; // Helpers //----------------------------------------------------------------------------- -// Helper: Lightweight std::vector<> like class to avoid dragging dependencies (also: Windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). -// *Important* Our implementation does NOT call C++ constructors/destructors. This is intentional, we do not require it but you have to be mindful of that. Do _not_ use this class as a std::vector replacement in your code! -template -class ImVector -{ -public: - int Size; - int Capacity; - T* Data; - - typedef T value_type; - typedef value_type* iterator; - typedef const value_type* const_iterator; - - inline ImVector() { Size = Capacity = 0; Data = NULL; } - inline ~ImVector() { if (Data) ImGui::MemFree(Data); } - inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } - inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; } - - inline bool empty() const { return Size == 0; } - inline int size() const { return Size; } - inline int capacity() const { return Capacity; } - inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } - inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } - - inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } - inline iterator begin() { return Data; } - inline const_iterator begin() const { return Data; } - inline iterator end() { return Data + Size; } - inline const_iterator end() const { return Data + Size; } - inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; } - inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; } - inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } - - inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } - inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } - inline void resize(int new_size,const value_type& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } - inline void reserve(int new_capacity) - { - if (new_capacity <= Capacity) - return; - value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); - if (Data) - { - memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); - ImGui::MemFree(Data); - } - Data = new_data; - Capacity = new_capacity; - } - - // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. - inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } - inline void pop_back() { IM_ASSERT(Size > 0); Size--; } - inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); } - inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } - inline iterator erase(const_iterator it, const_iterator it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(value_type)); Size -= (int)count; return Data + off; } - inline iterator erase_unsorted(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(value_type)); Size--; return Data + off; } - inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } - inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } - inline int index_from_pointer(const_iterator it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } -}; - // Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. // Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. From c3af134cc829f58a6606a147cd9815af33887608 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 6 Jan 2019 16:37:42 +0100 Subject: [PATCH 090/195] IO: Renamed InputCharacters[], marked internal as was always intended. AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful for automation to not have an upper limit on typing speed. Will later transition key/mouse to use the event queue later. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 26 ++++++++++++++------------ imgui.h | 8 ++++---- imgui_widgets.cpp | 10 +++++----- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bfbd0ca7..a56140e2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -70,6 +70,9 @@ Other Changes: - Error recovery: Missing calls to End(), pass the assert, should not lead to crashes or to the fallback Debug window appearing on screen, (#1651). - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. +- IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! +- IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful + for automation to not have an upper limit on typing speed. Will later transition key/mouse to use the event queue later. - Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value which is the same as the title bar height. - Demo: "Simple Layout" and "Style Editor" are now using tabs. diff --git a/imgui.cpp b/imgui.cpp index 07e26e0c..f426d75d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -363,6 +363,7 @@ 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. + - 2019/01/04 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). @@ -1164,22 +1165,23 @@ ImGuiIO::ImGuiIO() // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message void ImGuiIO::AddInputCharacter(ImWchar c) { - const int n = ImStrlenW(InputCharacters); - if (n + 1 < IM_ARRAYSIZE(InputCharacters)) + InputQueueCharacters.push_back(c); +} + +void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +{ + while (*utf8_chars != 0) { - InputCharacters[n] = c; - InputCharacters[n+1] = '\0'; + unsigned int c = 0; + utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); + if (c > 0 && c <= 0xFFFF) + InputQueueCharacters.push_back((ImWchar)c); } } -void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +void ImGuiIO::ClearInputCharacters() { - // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more - const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar); - ImWchar wchars[wchars_buf_len]; - ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL); - for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++) - AddInputCharacter(wchars[i]); + InputQueueCharacters.resize(0); } //----------------------------------------------------------------------------- @@ -3713,7 +3715,7 @@ void ImGui::EndFrame() // Clear Input data for next frame g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; - memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); + g.IO.InputQueueCharacters.resize(0); memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); } diff --git a/imgui.h b/imgui.h index eaf2c640..753382aa 100644 --- a/imgui.h +++ b/imgui.h @@ -1353,13 +1353,12 @@ struct ImGuiIO bool KeyAlt; // Keyboard modifier pressed: Alt bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). - ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). // Functions - IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[] - IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Add new characters into InputCharacters[] from an UTF-8 string - inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Clear the text input buffer manually + IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string + IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually //------------------------------------------------------------------ // Output - Retrieve after calling NewFrame() @@ -1399,6 +1398,7 @@ struct ImGuiIO float KeysDownDurationPrev[512]; // Previous duration the key has been down float NavInputsDownDuration[ImGuiNavInput_COUNT]; float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper. IMGUI_API ImGuiIO(); }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7f6b86e8..618de9bb 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3127,7 +3127,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) ImGuiContext& g = *GImGui; - const ImGuiIO& io = g.IO; + ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; @@ -3312,22 +3312,22 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) edit_state.SelectedAllMouseLock = false; - if (io.InputCharacters[0]) + if (io.InputQueueCharacters.Size > 0) { // Process text input (before we check for Return because using some IME will effectively send a Return?) // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); if (!ignore_inputs && is_editable && !user_nav_input_start) - for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++) + for (int n = 0; n < io.InputQueueCharacters.Size; n++) { // Insert character if they pass filtering - unsigned int c = (unsigned int)io.InputCharacters[n]; + unsigned int c = (unsigned int)io.InputQueueCharacters[n]; if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) edit_state.OnKeyPressed((int)c); } // Consume characters - memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); + io.InputQueueCharacters.resize(0); } } From 1353c74dcf79a7188845377a0f3479ffdf89638d Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 6 Jan 2019 16:37:57 +0100 Subject: [PATCH 091/195] Comments/formatting on obsolete stuff --- imgui.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/imgui.h b/imgui.h index 753382aa..e7d50777 100644 --- a/imgui.h +++ b/imgui.h @@ -1035,8 +1035,9 @@ enum ImGuiCol_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg, ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive - , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg + , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63] + , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg // [renamed in 1.53] + , ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive // [renamed in 1.51] //ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors. //ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate. #endif @@ -1336,7 +1337,7 @@ struct ImGuiIO // You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this. void (*RenderDrawListsFn)(ImDrawData* data); #else - // This is only here to keep ImGuiIO the same size, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h. + // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h. void* RenderDrawListsFnUnused; #endif @@ -1476,6 +1477,7 @@ struct ImGuiPayload //----------------------------------------------------------------------------- // Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -1483,14 +1485,14 @@ namespace ImGui { // OBSOLETED in 1.66 (from Sep 2018) static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } - // OBSOLETED in 1.63 (from Aug 2018) + // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018) static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } - // OBSOLETED in 1.61 (from Apr 2018) + // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018) IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0); IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0); IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0); - // OBSOLETED in 1.60 (from Dec 2017) + // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { (void)on_edge; (void)outward; IM_ASSERT(0); return pos; } @@ -1511,7 +1513,7 @@ namespace ImGui static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } } -typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent +typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; #endif @@ -1539,15 +1541,15 @@ struct ImGuiOnceUponAFrame }; // Helper: Macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces. -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Will obsolete -#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf) // OBSOLETED in 1.51, will remove! #endif // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" struct ImGuiTextFilter { IMGUI_API ImGuiTextFilter(const char* default_filter = ""); - IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; IMGUI_API void Build(); void Clear() { InputBuf[0] = 0; Build(); } From 5cb7ce20856c27b836cad7441b91e9b6ea760207 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 6 Jan 2019 16:50:23 +0100 Subject: [PATCH 092/195] Renamed ImFont::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 6 ++++-- imgui.h | 46 ++++++++++++++++++++++++------------------- imgui_draw.cpp | 19 +++++++++++------- misc/fonts/README.txt | 8 ++++---- 5 files changed, 48 insertions(+), 33 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a56140e2..95dd58f0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,7 @@ Breaking Changes: The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. - Made it illegal to call Begin("") with an empty string. This somehow accidentally worked before but had various undesirable side-effect as the window would have ID zero. In particular it is causing problems in viewport/docking branches. +- Renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). Other Changes: - Added BETA api for Tab Bar/Tabs widgets: (#261, #351) @@ -734,6 +735,7 @@ Breaking Changes: - Removed `IsItemRectHovered()`, `IsWindowRectHovered()` recently introduced in 1.51 which were merely the more consistent/correct names for the above functions which are now obsolete anyway. (#1382) - Changed `IsWindowHovered()` default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. (#1382) - Renamed imconfig.h's `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS` to `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` for consistency. +- Renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete). Other Changes: diff --git a/imgui.cpp b/imgui.cpp index f426d75d..a1c64193 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -363,7 +363,8 @@ 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. - - 2019/01/04 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! + - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! + - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). @@ -431,6 +432,7 @@ CODE removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). + - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete). - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! @@ -822,7 +824,7 @@ CODE // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need) ImVector ranges; - ImFontAtlas::GlyphRangesBuilder builder; + ImFontGlyphRangesBuilder builder; builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) builder.AddChar(0x7262); // Add a specific character builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges diff --git a/imgui.h b/imgui.h index e7d50777..2a26e27d 100644 --- a/imgui.h +++ b/imgui.h @@ -86,15 +86,17 @@ Index of this file: // Forward declarations and basic types //----------------------------------------------------------------------------- -struct ImDrawChannel; // Temporary storage for outputting drawing commands out of order, used by ImDrawList::ChannelsSplit() -struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call) -struct ImDrawData; // All draw command lists required to render the frame +struct ImDrawChannel; // Temporary storage for ImDrawList ot output draw commands out of order, used by ImDrawList::ChannelsSplit() +struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) +struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) -struct ImDrawVert; // A single vertex (20 bytes by default, override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) +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 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 struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) #ifndef ImTextureID typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) @@ -108,8 +110,8 @@ struct ImGuiPayload; // User data payload for drag and drop opera struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) struct ImGuiStorage; // Helper for key->value storage struct ImGuiStyle; // Runtime data for styling/colors -struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]") 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[,bbbb][,ccccc]") // Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. @@ -1902,7 +1904,7 @@ struct ImDrawData }; //----------------------------------------------------------------------------- -// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont) +// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) //----------------------------------------------------------------------------- struct ImFontConfig @@ -1939,6 +1941,19 @@ struct ImFontGlyph float U0, V0, U1, V1; // Texture coordinates }; +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +struct ImFontGlyphRangesBuilder +{ + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); } + bool GetBit(int n) const { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; } + void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array + void AddChar(ImWchar c) { SetBit(c); } // Add character + IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) + IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext + IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges +}; + enum ImFontAtlasFlags_ { ImFontAtlasFlags_None = 0, @@ -1995,7 +2010,7 @@ struct ImFontAtlas // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. - // NB: Consider using GlyphRangesBuilder to build glyph ranges from textual data. + // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs @@ -2004,19 +2019,6 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters - // Helpers to build glyph ranges from text data. Feed your application strings/characters to it then call BuildRanges(). - struct GlyphRangesBuilder - { - ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) - GlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); } - bool GetBit(int n) const { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; } - void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array - void AddChar(ImWchar c) { SetBit(c); } // Add character - IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) - IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext - IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges - }; - //------------------------------------------- // Custom Rectangles/Glyphs API //------------------------------------------- @@ -2065,6 +2067,10 @@ struct ImFontAtlas ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVector ConfigData; // Internal data int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETE 1.67+ +#endif }; // Font runtime data and rendering diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7bd85ab3..932c6ab6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -12,7 +12,8 @@ Index of this file: // [SECTION] Helpers ShadeVertsXXX functions // [SECTION] ImFontConfig // [SECTION] ImFontAtlas -// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder +// [SECTION] ImFontAtlas glyph ranges helpers +// [SECTION] ImFontGlyphRangesBuilder // [SECTION] ImFont // [SECTION] Internal Render Helpers // [SECTION] Decompression code @@ -2092,7 +2093,7 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* } //------------------------------------------------------------------------- -// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder +// [SECTION] ImFontAtlas glyph ranges helpers //------------------------------------------------------------------------- const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() @@ -2100,7 +2101,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() // Store 2500 regularly used characters for Simplified Chinese. // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 // This table covers 97.97% of all characters used during the month in July, 1987. - // You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) static const short accumulative_offsets_from_0x4E00[] = { @@ -2166,7 +2167,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() // 1946 common ideograms code points for Japanese // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this. - // You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) static const short accumulative_offsets_from_0x4E00[] = { @@ -2244,7 +2245,11 @@ const ImWchar* ImFontAtlas::GetGlyphRangesThai() return &ranges[0]; } -void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end) +//----------------------------------------------------------------------------- +// [SECTION] ImFontGlyphRangesBuilder +//----------------------------------------------------------------------------- + +void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) { while (text_end ? (text < text_end) : *text) { @@ -2258,14 +2263,14 @@ void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text } } -void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges) +void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) { for (; ranges[0]; ranges += 2) for (ImWchar c = ranges[0]; c <= ranges[1]; c++) AddChar(c); } -void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector* out_ranges) +void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) { for (int n = 0; n < 0x10000; n++) if (GetBit(n)) diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt index 236c3dd0..004dca3d 100644 --- a/misc/fonts/README.txt +++ b/misc/fonts/README.txt @@ -119,8 +119,8 @@ Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. Some solutions: - - 1) Reduce glyphs ranges by calculating them from source localization data. You can use ImFont::GlyphRangesBuilder for this purpose, - this will be the biggest win. + - 1) Reduce glyphs ranges by calculating them from source localization data. + You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win! - 2) You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size. - 3) Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). - 4) Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two. @@ -177,11 +177,11 @@ Also note that correct sRGB space blending will have an important effect on your BUILDING CUSTOM GLYPH RANGES --------------------------------------- -You can use the ImFontAtlas::GlyphRangesBuilder helper to create glyph ranges based on text input. +You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. ImVector ranges; - ImFontAtlas::GlyphRangesBuilder builder; + ImFontGlyphRangesBuilder builder; builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) builder.AddChar(0x7262); // Add a specific character builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges From acfa4050ec74378ecec87b3815e10aed50a9a245 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 6 Jan 2019 18:55:30 +0100 Subject: [PATCH 093/195] Tweak changelog + tweak internal render helper functions. --- docs/CHANGELOG.txt | 20 ++++++++++---------- imgui_draw.cpp | 3 ++- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 95dd58f0..42cccf76 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,25 +51,26 @@ Other Changes: - Demo: Added "Documents" example app showcasing possible use for tabs. This feature was merged from the Docking branch in order to allow the use of regular tabs in your code. (It does not provide the docking/splitting/merging of windows available in the Docking branch) -- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering - the ID, as a convenience to avoid using the ### operator. +- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, + as a convenience to avoid using the ### operator. In the Docking branch this also has an effect on tab closing behavior. - Window, Focus, Popup: Fixed an issue where closing a popup by clicking another window with the _NoMove flag would refocus the parent window of the popup instead of the newly clicked window. - Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. - Window: Contents size is preserved while a window contents is hidden (unless it is hidden for resizing purpose). - Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that - it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. -- Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). + it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-ends do. +- Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. This is ignored by window with no title bars (often popups). This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) - Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary keep the focus on the parent window, which could steal it from newly appearing windows. (#787) -- Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function itself - at the call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) -- Error recovery: Missing calls to End(), pass the assert, should not lead to crashes or to the fallback Debug window - appearing on screen, (#1651). +- Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function closer + to the user call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) + Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. + Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected + into e.g. an error log and stopping the script execution. - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. - IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful @@ -78,8 +79,7 @@ Other Changes: which is the same as the title bar height. - Demo: "Simple Layout" and "Style Editor" are now using tabs. - Demo: Added a few more things under "Child windows" (changing ImGuiCol_ChildBg, positioning child, using IsItemHovered after a child). -- Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file - to ease integration. +- Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file to ease integration. - Examples: Allegro 5: Properly destroy globals on shutdown to allow for restart. (#2262) [@DomRe] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 932c6ab6..6853ce0a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2953,8 +2953,9 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im // FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, // and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match // the boldness or positioning of what the font uses... -void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col) +void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) { + ImFont* font = draw_list->_Data->Font; pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); for (int dot_n = 0; dot_n < count; dot_n++) draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); diff --git a/imgui_internal.h b/imgui_internal.h index a4edaf85..f035854a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1370,7 +1370,7 @@ namespace ImGui IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow); IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); - IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col); + IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col); // Widgets IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 618de9bb..2c2c8f0e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6542,7 +6542,7 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, const float ellipsis_x = text_pixel_clip_bb.Min.x + label_size_clipped_x + 1.0f; if (!close_button_visible && ellipsis_x + ellipsis_width <= bb.Max.x) - RenderPixelEllipsis(draw_list, g.Font, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text)); + RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text)); } else { From 50faccf764cbd68e1c364014e6a66a818c899ab9 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 17:33:02 +0100 Subject: [PATCH 094/195] Demo: Log: Comments. Using clipper. Not linking with rand() anymore. --- docs/TODO.txt | 1 + imgui_demo.cpp | 75 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 4c2a2037..8b60c057 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -31,6 +31,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. - window: investigate better auto-positioning for new windows. - 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?). + - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse) - scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet. - scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y). (2017-08-20: can't repro) - scrolling/style: shadows on scrollable areas to denote that there is more contents diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a5f8f86c..856531b9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3375,10 +3375,15 @@ struct ExampleAppLog { ImGuiTextBuffer Buf; ImGuiTextFilter Filter; - ImVector LineOffsets; // Index to lines offset + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines bool ScrollToBottom; - void Clear() { Buf.clear(); LineOffsets.clear(); } + void Clear() + { + Buf.clear(); + LineOffsets.clear(); + LineOffsets.push_back(0); + } void AddLog(const char* fmt, ...) IM_FMTARGS(2) { @@ -3389,13 +3394,12 @@ struct ExampleAppLog va_end(args); for (int new_size = Buf.size(); old_size < new_size; old_size++) if (Buf[old_size] == '\n') - LineOffsets.push_back(old_size); + LineOffsets.push_back(old_size + 1); ScrollToBottom = true; } void Draw(const char* title, bool* p_open = NULL) { - ImGui::SetNextWindowSize(ImVec2(500,400), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open)) { ImGui::End(); @@ -3408,24 +3412,47 @@ struct ExampleAppLog Filter.Draw("Filter", -100.0f); ImGui::Separator(); ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); - if (copy) ImGui::LogToClipboard(); + if (copy) + ImGui::LogToClipboard(); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); if (Filter.IsActive()) { - const char* buf_begin = Buf.begin(); - const char* line = buf_begin; - for (int line_no = 0; line != NULL; line_no++) + for (int line_no = 0; line_no < LineOffsets.Size; line_no++) { - const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL; - if (Filter.PassFilter(line, line_end)) - ImGui::TextUnformatted(line, line_end); - line = line_end && line_end[1] ? line_end + 1 : NULL; + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + if (Filter.PassFilter(line_start, line_end)) + ImGui::TextUnformatted(line_start, line_end); } } else { - ImGui::TextUnformatted(Buf.begin()); + // The simplest and easy way to display the entire buffer: + // ImGui::TextUnformatted(buf_begin, buf_end); + // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines. + // Here we instead demonstrate using the clipper to only process lines that are within the visible area. + // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended. + // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, + // both of which we can handle since we an array pointing to the beginning of each line of text. + // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper. + // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries) + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); } + ImGui::PopStyleVar(); if (ScrollToBottom) ImGui::SetScrollHereY(1.0f); @@ -3440,15 +3467,23 @@ static void ShowExampleAppLog(bool* p_open) { static ExampleAppLog log; - // Demo: add random items (unless Ctrl is held) - static double last_time = -1.0; - double time = ImGui::GetTime(); - if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl) + // For the demo: add a debug button before the normal log window contents + // We take advantage of the fact that multiple calls to Begin()/End() are appending to the same window. + ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); + ImGui::Begin("Example: Log", p_open); + if (ImGui::SmallButton("Add 5 entries")) { - const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" }; - log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount()); - last_time = time; + static int counter = 0; + for (int n = 0; n < 5; n++) + { + const char* categories[3] = { "info", "warn", "error" }; + const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]); + counter++; + } } + ImGui::End(); log.Draw("Example: Log", p_open); } From 1ae7f8849508c82b3b496ac636cb5069fc348053 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 17:52:16 +0100 Subject: [PATCH 095/195] Tabs: Added ImGuiTabBarFlags_NoTooltip flag. (#261, #351) + added helpful assert --- imgui.h | 5 +++-- imgui_widgets.cpp | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 2a26e27d..82c0a62e 100644 --- a/imgui.h +++ b/imgui.h @@ -806,8 +806,9 @@ enum ImGuiTabBarFlags_ ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, - ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 5, // Resize tabs when they don't fit - ImGuiTabBarFlags_FittingPolicyScroll = 1 << 6, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2c2c8f0e..bdf4991e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6241,6 +6241,7 @@ void ImGui::EndTabItem() IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!"); ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); + IM_ASSERT(tab_bar->LastTabItemIdx >= 0 && "Needs to be called between BeginTabItem() and EndTabItem()"); ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) g.CurrentWindow->IDStack.pop_back(); @@ -6422,7 +6423,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer) if (g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > 0.50f) - SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); return tab_contents_visible; } From 3997e8b555ebb2b263dde7dce0d626d9a08fca29 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 22:46:42 +0100 Subject: [PATCH 096/195] Fixed animated window titles from being updated when displayed in the CTRL+Tab list. + Adding overkill helpers for reusing buffers. (#787) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 39 ++++++++++++++++++++++++++++++++++----- imgui_internal.h | 2 ++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 42cccf76..053c8ea2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -66,6 +66,7 @@ Other Changes: - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) - Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary keep the focus on the parent window, which could steal it from newly appearing windows. (#787) +- Nav: Fixed animated window titles from being updated when displayed in the CTRL+Tab list. (#787) - Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function closer to the user call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. diff --git a/imgui.cpp b/imgui.cpp index a1c64193..3f9ce8be 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1259,11 +1259,25 @@ void ImStrncpy(char* dst, const char* src, size_t count) dst[count-1] = 0; } -char* ImStrdup(const char *str) +char* ImStrdup(const char* str) { - size_t len = strlen(str) + 1; - void* buf = ImGui::MemAlloc(len); - return (char*)memcpy(buf, (const void*)str, len); + size_t len = strlen(str); + void* buf = ImGui::MemAlloc(len + 1); + return (char*)memcpy(buf, (const void*)str, len + 1); +} + +char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) +{ + size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; + size_t src_size = strlen(src) + 1; + if (dst_buf_size < src_size) + { + ImGui::MemFree(dst); + dst = (char*)ImGui::MemAlloc(src_size); + if (p_dst_size) + *p_dst_size = src_size; + } + return (char*)memcpy(dst, (const void*)src, src_size); } const char* ImStrchrRange(const char* str, const char* str_end, char c) @@ -1367,7 +1381,9 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) } #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS -// Pass data_size==0 for zero-terminated strings +// Pass data_size == 0 for zero-terminated strings, data_size > 0 for non-string data. +// Pay attention that data_size==0 will yield different results than passing strlen(data) because the zero-terminated codepath handles ###. +// This should technically be split into two distinct functions (ImHashData/ImHashStr), perhaps once we remove the silly static variable. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. ImU32 ImHash(const void* data, int data_size, ImU32 seed) { @@ -2391,6 +2407,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) WindowPadding = ImVec2(0.0f, 0.0f); WindowRounding = 0.0f; WindowBorderSize = 0.0f; + NameBufLen = (int)strlen(name) + 1; MoveId = GetID("#MOVE"); ChildId = 0; Scroll = ImVec2(0.0f, 0.0f); @@ -4802,6 +4819,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->LastFrameActive = current_frame; window->IDStack.resize(1); + // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). + // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. + bool window_title_visible_elsewhere = false; + if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) + { + size_t buf_len = (size_t)window->NameBufLen; + window->Name = ImStrdupcpy(window->Name, &buf_len, name); + window->NameBufLen = (int)buf_len; + } + // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS // Update contents size from last frame for auto-fitting (or use explicit size) diff --git a/imgui_internal.h b/imgui_internal.h index f035854a..213ef3dc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -143,6 +143,7 @@ IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); IMGUI_API int ImStrlenW(const ImWchar* str); IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line @@ -1071,6 +1072,7 @@ struct IMGUI_API ImGuiWindow ImVec2 WindowPadding; // Window padding at the time of begin. float WindowRounding; // Window rounding at the time of begin. float WindowBorderSize; // Window border size at the time of begin. + int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! ImGuiID MoveId; // == window->GetID("#MOVE") ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) ImVec2 Scroll; From c2db7f63bd7d07812ef73b441448fc54ab2ea084 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 23:45:07 +0100 Subject: [PATCH 097/195] Selectable() should have an ID even though they are disabled, to be consistent with other widgets. Not sure of the reasoning ~1.41 which made this turn to 0. --- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 213ef3dc..7429c34c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -331,8 +331,8 @@ enum ImGuiItemStatusFlags_ // FIXME: this is in development, not exposed/functional as a generic feature yet. enum ImGuiLayoutType_ { - ImGuiLayoutType_Vertical, - ImGuiLayoutType_Horizontal + ImGuiLayoutType_Vertical = 0, + ImGuiLayoutType_Horizontal = 1, }; enum ImGuiAxis diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bdf4991e..dd1c2eb4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -282,10 +282,12 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set - if (need_wrap) PushTextWrapPos(0.0f); + bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + if (need_backup) + PushTextWrapPos(0.0f); TextV(fmt, args); - if (need_wrap) PopTextWrapPos(); + if (need_backup) + PopTextWrapPos(); } void ImGui::LabelText(const char* label, const char* fmt, ...) @@ -5030,7 +5032,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl bb.Min.y -= spacing_U; bb.Max.x += spacing_R; bb.Max.y += spacing_D; - if (!ItemAdd(bb, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id)) + if (!ItemAdd(bb, id)) { if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) PushColumnClipRect(); From b33977bc15d7edeccbbd6a05dd7a5099c835f33f Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 23:59:05 +0100 Subject: [PATCH 098/195] Tests: Reworking hook prototypes for imgui-test to be faster and multi-context friendly. --- imgui.cpp | 7 ++++--- imgui_internal.h | 10 +++++----- imgui_widgets.cpp | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3f9ce8be..bcd4daf7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2697,7 +2697,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_ItemAdd(bb, id); + if (id != 0) + ImGuiTestEngineHook_ItemAdd(&g, bb, id); #endif // Clipping test @@ -3251,7 +3252,7 @@ void ImGui::NewFrame() ImGuiContext& g = *GImGui; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_PreNewFrame(); + ImGuiTestEngineHook_PreNewFrame(&g); #endif // Check user data @@ -3427,7 +3428,7 @@ void ImGui::NewFrame() g.FrameScopePushedImplicitWindow = true; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_PostNewFrame(); + ImGuiTestEngineHook_PostNewFrame(&g); #endif } diff --git a/imgui_internal.h b/imgui_internal.h index 7429c34c..97520ce3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1429,11 +1429,11 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch // Test engine hooks (imgui-test) //#define IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE -extern void ImGuiTestEngineHook_PreNewFrame(); -extern void ImGuiTestEngineHook_PostNewFrame(); -extern void ImGuiTestEngineHook_ItemAdd(const ImRect& bb, ImGuiID id); -extern void ImGuiTestEngineHook_ItemInfo(ImGuiID id, const char* label, int flags); -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(_ID, _LABEL, _FLAGS) // Register status flags +extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, int flags); +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags #else #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) #endif diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dd1c2eb4..2edc5d3c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -282,7 +282,7 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set if (need_backup) PushTextWrapPos(0.0f); TextV(fmt, args); @@ -399,8 +399,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = window; #ifdef IMGUI_ENABLE_TEST_ENGINE - if (window->DC.LastItemId != id) - ImGuiTestEngineHook_ItemAdd(bb, id); + if (id != 0 && window->DC.LastItemId != id) + ImGuiTestEngineHook_ItemAdd(&g, bb, id); #endif bool pressed = false; From 57b1622afcf5a1afef3da0664845118f1da942fa Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 15:28:33 +0100 Subject: [PATCH 099/195] Added IMGUI_USE_STB_SPRINTF (undocumented) (#1038) --- imgui.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index bcd4daf7..2e7ceb6d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1351,6 +1351,11 @@ void ImStrTrimBlanks(char* buf) // B) When buf==NULL vsnprintf() will return the output size. #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +#ifdef IMGUI_USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "imstb_sprintf.h" +#endif + #if defined(_MSC_VER) && !defined(vsnprintf) #define vsnprintf _vsnprintf #endif @@ -1359,7 +1364,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) { va_list args; va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else int w = vsnprintf(buf, buf_size, fmt, args); +#endif va_end(args); if (buf == NULL) return w; @@ -1371,7 +1380,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) { +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else int w = vsnprintf(buf, buf_size, fmt, args); +#endif if (buf == NULL) return w; if (w == -1 || w >= (int)buf_size) From f53cd3ee0f5a08e3115420d98d3d89118a0fcf57 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 16:26:45 +0100 Subject: [PATCH 100/195] Internals: LowerBound: Use raw pointer typedefs, we never use iterator anywhere else in the codebase. Demo: Typo. C98 fix. --- imgui.cpp | 26 +++++++++++++------------- imgui_demo.cpp | 2 +- imgui_internal.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e7ceb6d..e8194f87 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1795,15 +1795,15 @@ ImU32 ImGui::GetColorU32(ImU32 col) //----------------------------------------------------------------------------- // std::lower_bound but without the bullshit -static ImVector::iterator LowerBound(ImVector& data, ImGuiID key) +static ImGuiStorage::Pair* LowerBound(ImVector& data, ImGuiID key) { - ImVector::iterator first = data.begin(); - ImVector::iterator last = data.end(); + ImGuiStorage::Pair* first = data.Data; + ImGuiStorage::Pair* last = data.Data + data.Size; size_t count = (size_t)(last - first); while (count > 0) { size_t count2 = count >> 1; - ImVector::iterator mid = first + count2; + ImGuiStorage::Pair* mid = first + count2; if (mid->key < key) { first = ++mid; @@ -1836,7 +1836,7 @@ void ImGuiStorage::BuildSortByKey() int ImGuiStorage::GetInt(ImGuiID key, int default_val) const { - ImVector::iterator it = LowerBound(const_cast&>(Data), key); + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) return default_val; return it->val_i; @@ -1849,7 +1849,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const { - ImVector::iterator it = LowerBound(const_cast&>(Data), key); + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) return default_val; return it->val_f; @@ -1857,7 +1857,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const void* ImGuiStorage::GetVoidPtr(ImGuiID key) const { - ImVector::iterator it = LowerBound(const_cast&>(Data), key); + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) return NULL; return it->val_p; @@ -1866,7 +1866,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const // References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) it = Data.insert(it, Pair(key, default_val)); return &it->val_i; @@ -1879,7 +1879,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) it = Data.insert(it, Pair(key, default_val)); return &it->val_f; @@ -1887,7 +1887,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) it = Data.insert(it, Pair(key, default_val)); return &it->val_p; @@ -1896,7 +1896,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) void ImGuiStorage::SetInt(ImGuiID key, int val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) { Data.insert(it, Pair(key, val)); @@ -1912,7 +1912,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val) void ImGuiStorage::SetFloat(ImGuiID key, float val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) { Data.insert(it, Pair(key, val)); @@ -1923,7 +1923,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val) void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) { Data.insert(it, Pair(key, val)); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 856531b9..dcaa3660 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4027,7 +4027,7 @@ void ShowExampleAppDocuments(bool* p_open) { static ExampleAppDocuments app; - if (!ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar)) + if (!ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar)) { ImGui::End(); return; diff --git a/imgui_internal.h b/imgui_internal.h index 97520ce3..538759ce 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -332,7 +332,7 @@ enum ImGuiItemStatusFlags_ enum ImGuiLayoutType_ { ImGuiLayoutType_Vertical = 0, - ImGuiLayoutType_Horizontal = 1, + ImGuiLayoutType_Horizontal = 1 }; enum ImGuiAxis From 9ad341902da34e462b73e8bca85e39179f210e6c Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 17:37:22 +0100 Subject: [PATCH 101/195] ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible. --- docs/CHANGELOG.txt | 2 + imgui.h | 8 ++-- imgui_draw.cpp | 116 +++++++++++++++++++++++++-------------------- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 053c8ea2..66ed9545 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other Changes: Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected into e.g. an error log and stopping the script execution. +- ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible. + (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.) - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. - IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful diff --git a/imgui.h b/imgui.h index 82c0a62e..4298b3b8 100644 --- a/imgui.h +++ b/imgui.h @@ -1847,11 +1847,11 @@ struct ImDrawList IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); // Stateful path API, add points then finish with PathFillConvex() or PathStroke() - inline void PathClear() { _Path.resize(0); } + inline void PathClear() { _Path.Size = 0; } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } - inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } - inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); } // 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); PathClear(); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } + 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& centre, float radius, float a_min, float a_max, int num_segments = 10); IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6853ce0a..9833590f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -656,7 +656,13 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c _IdxWritePtr += 6; } +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds. +// Those macros expects l-values. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } +#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } } + // TODO: Thickness anti-aliased lines cap are missing their AA fringe. +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) { if (points_count < 2) @@ -686,10 +692,11 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 for (int i1 = 0; i1 < count; i1++) { const int i2 = (i1+1) == points_count ? 0 : i1+1; - ImVec2 diff = points[i2] - points[i1]; - diff *= ImInvLength(diff, 1.0f); - temp_normals[i1].x = diff.y; - temp_normals[i1].y = -diff.x; + float dx = points[i2].x - points[i1].x; + float dy = points[i2].y - points[i1].y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i1].x = dy; + temp_normals[i1].y = -dx; } if (!closed) temp_normals[points_count-1] = temp_normals[points_count-2]; @@ -712,17 +719,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3; // Average normals - ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) - { - float scale = 1.0f / dmr2; - if (scale > 100.0f) scale = 100.0f; - dm *= scale; - } - dm *= AA_SIZE; - temp_points[i2*2+0] = points[i2] + dm; - temp_points[i2*2+1] = points[i2] - dm; + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f) + dm_x *= AA_SIZE; + dm_y *= AA_SIZE; + + // Add temporary vertexes + ImVec2* out_vtx = &temp_points[i2*2]; + out_vtx[0].x = points[i2].x + dm_x; + out_vtx[0].y = points[i2].y + dm_y; + out_vtx[1].x = points[i2].x - dm_x; + out_vtx[1].y = points[i2].y - dm_y; // Add indexes _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); @@ -766,20 +774,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4; // Average normals - ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) - { - float scale = 1.0f / dmr2; - if (scale > 100.0f) scale = 100.0f; - dm *= scale; - } - ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE); - ImVec2 dm_in = dm * half_inner_thickness; - temp_points[i2*4+0] = points[i2] + dm_out; - temp_points[i2*4+1] = points[i2] + dm_in; - temp_points[i2*4+2] = points[i2] - dm_in; - temp_points[i2*4+3] = points[i2] - dm_out; + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f); + float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); + float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); + float dm_in_x = dm_x * half_inner_thickness; + float dm_in_y = dm_y * half_inner_thickness; + + // Add temporary vertexes + ImVec2* out_vtx = &temp_points[i2*4]; + out_vtx[0].x = points[i2].x + dm_out_x; + out_vtx[0].y = points[i2].y + dm_out_y; + out_vtx[1].x = points[i2].x + dm_in_x; + out_vtx[1].y = points[i2].y + dm_in_y; + out_vtx[2].x = points[i2].x - dm_in_x; + out_vtx[2].y = points[i2].y - dm_in_y; + out_vtx[3].x = points[i2].x - dm_out_x; + out_vtx[3].y = points[i2].y - dm_out_y; // Add indexes _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); @@ -817,11 +829,13 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 const int i2 = (i1+1) == points_count ? 0 : i1+1; const ImVec2& p1 = points[i1]; const ImVec2& p2 = points[i2]; - ImVec2 diff = p2 - p1; - diff *= ImInvLength(diff, 1.0f); - const float dx = diff.x * (thickness * 0.5f); - const float dy = diff.y * (thickness * 0.5f); + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (thickness * 0.5f); + dy *= (thickness * 0.5f); + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; @@ -836,6 +850,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 } } +// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) { if (points_count < 3) @@ -867,10 +882,11 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun { const ImVec2& p0 = points[i0]; const ImVec2& p1 = points[i1]; - ImVec2 diff = p1 - p0; - diff *= ImInvLength(diff, 1.0f); - temp_normals[i0].x = diff.y; - temp_normals[i0].y = -diff.x; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i0].x = dy; + temp_normals[i0].y = -dx; } for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) @@ -878,19 +894,15 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun // Average normals const ImVec2& n0 = temp_normals[i0]; const ImVec2& n1 = temp_normals[i1]; - ImVec2 dm = (n0 + n1) * 0.5f; - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) - { - float scale = 1.0f / dmr2; - if (scale > 100.0f) scale = 100.0f; - dm *= scale; - } - dm *= AA_SIZE * 0.5f; + float dm_x = (n0.x + n1.x) * 0.5f; + float dm_y = (n0.y + n1.y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f); + dm_x *= AA_SIZE * 0.5f; + dm_y *= AA_SIZE * 0.5f; // Add vertices - _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner - _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer _VtxWritePtr += 2; // Add indexes for fringes @@ -2422,7 +2434,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const { if (c >= IndexLookup.Size) return FallbackGlyph; - const ImWchar i = IndexLookup[c]; + const ImWchar i = IndexLookup.Data[c]; if (i == (ImWchar)-1) return FallbackGlyph; return &Glyphs.Data[i]; @@ -2432,7 +2444,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const { if (c >= IndexLookup.Size) return NULL; - const ImWchar i = IndexLookup[c]; + const ImWchar i = IndexLookup.Data[c]; if (i == (ImWchar)-1) return NULL; return &Glyphs.Data[i]; @@ -2492,7 +2504,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } } - const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX); + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); if (ImCharIsBlankW(c)) { if (inside_word) @@ -2609,7 +2621,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale; + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; if (line_width + char_width >= max_width) { s = prev_s; From 61a99f994e7127b1b3e8bba53fba2037841a60dc Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 18:23:28 +0100 Subject: [PATCH 102/195] Minot internal tweaks, comments --- imgui.cpp | 4 +++- imgui_widgets.cpp | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e8194f87..12a10b0b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1351,6 +1351,7 @@ void ImStrTrimBlanks(char* buf) // B) When buf==NULL vsnprintf() will return the output size. #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +//#define IMGUI_USE_STB_SPRINTF #ifdef IMGUI_USE_STB_SPRINTF #define STB_SPRINTF_IMPLEMENTATION #include "imstb_sprintf.h" @@ -2664,7 +2665,8 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y) const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); - window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2edc5d3c..1fbee11c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -204,7 +204,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) } ImRect bb(text_pos, text_pos + text_size); - ItemSize(bb); + ItemSize(text_size); ItemAdd(bb, 0); } else @@ -548,7 +548,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); const ImRect bb(pos, pos + size); - ItemSize(bb, style.FramePadding.y); + ItemSize(size, style.FramePadding.y); if (!ItemAdd(bb, id)) return false; @@ -602,7 +602,7 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) const ImGuiID id = window->GetID(str_id); ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); - ItemSize(bb); + ItemSize(size); if (!ItemAdd(bb, id)) return false; From 289569ef278a1beff0987a6d128227d33ce15115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 10 Jan 2019 14:58:59 +0100 Subject: [PATCH 103/195] Update link to Magnum bindings. (#2269) The various community projects that integrated Dear ImGui into Magnum were merged together and are now an official part of the engine. --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index c40aaf54..5f9a188c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -147,7 +147,7 @@ Frameworks: - OpenSceneGraph/OSG: [gist](https://gist.github.com/fulezi/d2442ca7626bf270226014501357042c) - ORX: [pr #1843](https://github.com/ocornut/imgui/pull/1843) - LÖVE+Lua: [love-imgui](https://github.com/slages/love-imgui) -- Magnum: [magnum-imgui](https://github.com/lecopivo/magnum-imgui), [MagnumImguiPort](https://github.com/lecopivo/MagnumImguiPort) +- Magnum: [ImGuiIntegration](https://doc.magnum.graphics/magnum/namespaceMagnum_1_1ImGuiIntegration.html) ([example](https://doc.magnum.graphics/magnum/examples-imgui.html)) - NanoRT: [syoyo/imgui](https://github.com/syoyo/imgui/tree/nanort) - Qt3d: [imgui-qt3d](https://github.com/alpqr/imgui-qt3d), QOpenGLWindow [qtimgui](https://github.com/ocornut/imgui/issues/1910) - SFML: [imgui-sfml](https://github.com/EliasD/imgui-sfml) From 81eaa497732d72c569604ff1d3cb73da677c5a85 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:14:51 +0100 Subject: [PATCH 104/195] Internals: Added comment index in imgui_internal.h --- imgui_internal.h | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 538759ce..ee266441 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -6,8 +6,27 @@ // #define IMGUI_DEFINE_MATH_OPERATORS // To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) +/* + +Index of this file: +// Header mess +// Forward declarations +// STB libraries includes +// Context pointer +// Generic helpers +// Misc data structures +// Main imgui context +// Tab bar, tab item +// Internal API + +*/ + #pragma once +//----------------------------------------------------------------------------- +// Header mess +//----------------------------------------------------------------------------- + #ifndef IMGUI_VERSION #error Must include imgui.h before imgui_internal.h #endif @@ -30,7 +49,7 @@ #endif //----------------------------------------------------------------------------- -// Forward Declarations +// Forward declarations //----------------------------------------------------------------------------- struct ImRect; // An axis-aligned rectangle (2 points) @@ -68,7 +87,7 @@ typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() //------------------------------------------------------------------------- -// STB libraries +// STB libraries includes //------------------------------------------------------------------------- namespace ImGuiStb @@ -84,7 +103,7 @@ namespace ImGuiStb } // namespace ImGuiStb //----------------------------------------------------------------------------- -// Context +// Context pointer //----------------------------------------------------------------------------- #ifndef GImGui @@ -92,7 +111,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe #endif //----------------------------------------------------------------------------- -// Helpers +// Generic helpers //----------------------------------------------------------------------------- #define IM_PI 3.14159265358979323846f @@ -242,7 +261,7 @@ struct IMGUI_API ImPool }; //----------------------------------------------------------------------------- -// Types +// Misc data structures //----------------------------------------------------------------------------- // 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) @@ -1172,7 +1191,7 @@ struct ImGuiItemHoveredDataBackup }; //----------------------------------------------------------------------------- -// Tab Bar, Tab Item +// Tab bar, tab item //----------------------------------------------------------------------------- enum ImGuiTabBarFlagsPrivate_ From 1f6e0b2f9818f4475d119d587352c83e90786618 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 9 Jan 2019 14:11:31 +0100 Subject: [PATCH 105/195] ImVector: Made a struct. Using T/T* in the code instead of value_type/iterator. Renamed index_from_pointer() to index_from_ptr() (was not documented, added in 1.63, users not supposed to use ImVector, hopefully not a big deal). --- imgui.cpp | 4 +-- imgui.h | 84 ++++++++++++++++++++++++----------------------- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 4 files changed, 47 insertions(+), 45 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 12a10b0b..c9b4188b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4384,7 +4384,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) { // Retrieve settings from .ini file - window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings); + window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); window->Pos = ImFloor(settings->Pos); window->Collapsed = settings->Collapsed; @@ -8940,7 +8940,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting if (!settings) { settings = ImGui::CreateNewWindowSettings(window->Name); - window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings); + window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); } IM_ASSERT(settings->ID == window->ID); settings->Pos = window->Pos; diff --git a/imgui.h b/imgui.h index 4298b3b8..d790b6f4 100644 --- a/imgui.h +++ b/imgui.h @@ -1157,55 +1157,57 @@ enum ImGuiCond_ // Helper: ImVector<> // Lightweight std::vector<>-like class to avoid dragging dependencies (also: some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. +// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. // Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, // do NOT use this class as a std::vector replacement in your own code! //----------------------------------------------------------------------------- template -class ImVector +struct ImVector { -public: - int Size; - int Capacity; - T* Data; + int Size; + int Capacity; + T* Data; + // Provide standard typedefs but we don't use them ourselves. typedef T value_type; typedef value_type* iterator; typedef const value_type* const_iterator; - inline ImVector() { Size = Capacity = 0; Data = NULL; } - inline ~ImVector() { if (Data) ImGui::MemFree(Data); } - inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } - inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; } - - inline bool empty() const { return Size == 0; } - inline int size() const { return Size; } - inline int capacity() const { return Capacity; } - inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } - inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } - - inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } - inline iterator begin() { return Data; } - inline const_iterator begin() const { return Data; } - inline iterator end() { return Data + Size; } - inline const_iterator end() const { return Data + Size; } - inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; } - inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; } - inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } - - inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } - inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } - inline void resize(int new_size,const value_type& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + // Constructors, destructor + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) ImGui::MemFree(Data); } + + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int capacity() const { return Capacity; } + inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } + + inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return Data + Size; } + inline const T* end() const { return Data + Size; } + inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; - value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); + T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { - memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); + memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; @@ -1213,15 +1215,15 @@ public: } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. - inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } - inline void pop_back() { IM_ASSERT(Size > 0); Size--; } - inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); } - inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } - inline iterator erase(const_iterator it, const_iterator it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(value_type)); Size -= (int)count; return Data + off; } - inline iterator erase_unsorted(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(value_type)); Size--; return Data + off; } - inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } - inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } - inline int index_from_pointer(const_iterator it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } + inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } }; //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index ee266441..51f3a3f7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1240,7 +1240,7 @@ struct ImGuiTabBar short LastTabItemIdx; // For BeginTabItem()/EndTabItem() ImGuiTabBar(); - int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_pointer(tab); } + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } }; //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1fbee11c..d65a420b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6286,7 +6286,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, tab->Width = size.x; tab_is_new = true; } - tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_pointer(tab); + tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); tab->WidthContents = size.x; const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); From 7ffbcfe46725985e62665d637add60e091a5e64c Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 9 Jan 2019 15:56:37 +0100 Subject: [PATCH 106/195] ImVector: Made reserve() another silly one-liner. It's not longer than other functions and our weird obsessions deserve to be carried with stringent consistence. + Comments --- imgui.h | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index d790b6f4..3cac4336 100644 --- a/imgui.h +++ b/imgui.h @@ -1200,19 +1200,7 @@ struct ImVector inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } - inline void reserve(int new_capacity) - { - if (new_capacity <= Capacity) - return; - T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); - if (Data) - { - memcpy(new_data, Data, (size_t)Size * sizeof(T)); - ImGui::MemFree(Data); - } - Data = new_data; - Capacity = new_capacity; - } + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } From e4c19f5af18f167f52cb67810235c8125b0a8340 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:15:29 +0100 Subject: [PATCH 107/195] ImFontGlyphRangesBuilder: Using 32-bits fields for storage instead of 8-bit ones, comments, todo. --- docs/TODO.txt | 1 + imgui.h | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 8b60c057..5e3f73ff 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -319,6 +319,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - optimization: replace vsnprintf with stb_printf? or enable the defines/infrastructure to allow it (#1038) - optimization: add clipping for multi-component widgets (SliderFloatX, ColorEditX, etc.). one problem is that nav branch can't easily clip parent group when there is a move request. - optimization: add a flag to disable most of rendering, for the case where the user expect to skip it (#335) + - optimization: fully covered window (covered by another with non-translucent bg + WindowRounding worth of padding) may want to clip rendering. - optimization: use another hash function than crc32, e.g. FNV1a - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimization: turn some the various stack vectors into statically-sized arrays diff --git a/imgui.h b/imgui.h index 3cac4336..dad97c6f 100644 --- a/imgui.h +++ b/imgui.h @@ -13,14 +13,14 @@ Index of this file: // Forward declarations and basic types // ImGui API (Dear ImGui end-user API) // Flags & Enumerations -// ImVector +// ImVector<> // ImGuiStyle // ImGuiIO // Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) // Obsolete functions // Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) -// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont) +// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) */ @@ -1155,11 +1155,11 @@ enum ImGuiCond_ //----------------------------------------------------------------------------- // Helper: ImVector<> -// Lightweight std::vector<>-like class to avoid dragging dependencies (also: some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. // Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. // Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, -// do NOT use this class as a std::vector replacement in your own code! +// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. //----------------------------------------------------------------------------- template @@ -1933,12 +1933,14 @@ struct ImFontGlyph }; // Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. struct ImFontGlyphRangesBuilder { - ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) - ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); } - bool GetBit(int n) const { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; } - void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + + ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 32); memset(UsedChars.Data, 0, 0x10000 / 32); } + bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array void AddChar(ImWchar c) { SetBit(c); } // Add character IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext From 7ed8e55fc75da2c0ba81bcb5e3c2f6528641a671 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 9 Jan 2019 16:59:48 +0100 Subject: [PATCH 108/195] ImVector: Added size_in_bytes() helper. --- imgui.h | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.h b/imgui.h index dad97c6f..9da2e9f2 100644 --- a/imgui.h +++ b/imgui.h @@ -1182,6 +1182,7 @@ struct ImVector inline bool empty() const { return Size == 0; } inline int size() const { return Size; } + inline int size_in_bytes() const { return Size * (int)sizeof(T); } inline int capacity() const { return Capacity; } inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } From 56caf7da29d3de46981b5d6b6bc7b0e91c66fba3 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:16:30 +0100 Subject: [PATCH 109/195] imgui_freetype: Minor tweaks and comments. --- misc/freetype/imgui_freetype.cpp | 30 ++++++++++++++++-------------- misc/freetype/imgui_freetype.h | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 33bdb140..70039491 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -1,4 +1,4 @@ -// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui +// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype // Original code by @Vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut @@ -20,15 +20,15 @@ // TODO: // - Output texture has excessive resolution (lots of vertical waste). // - FreeType's memory allocator is not overridden. -// - cfg.OversampleH, OversampleV are ignored (but perhaps not so necessary with this rasterizer). +// - cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). #include "imgui_freetype.h" #include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*, #include #include -#include FT_FREETYPE_H -#include FT_GLYPH_H -#include FT_SYNTHESIS_H +#include FT_FREETYPE_H // +#include FT_GLYPH_H // +#include FT_SYNTHESIS_H // #ifdef _MSC_VER #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) @@ -96,8 +96,8 @@ namespace // NB: No ctor/dtor, explicitly call Init()/Shutdown() struct FreeTypeFont { - bool Init(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. - void Shutdown(); + bool Create(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + void Destroy(); void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size bool CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap); @@ -114,7 +114,7 @@ namespace // From SDL_ttf: Handy routines for converting from fixed point #define FT_CEIL(X) (((X + 63) & -64) / 64) - bool FreeTypeFont::Init(const ImFontConfig& cfg, unsigned int extra_user_flags) + bool FreeTypeFont::Create(const ImFontConfig& cfg, unsigned int extra_user_flags) { // FIXME: substitute allocator FT_Error error = FT_Init_FreeType(&FreetypeLibrary); @@ -130,7 +130,7 @@ namespace memset(&Info, 0, sizeof(Info)); SetPixelHeight((uint32_t)cfg.SizePixels); - // Convert to freetype flags (nb: Bold and Oblique are processed separately) + // Convert to FreeType flags (NB: Bold and Oblique are processed separately) UserFlags = cfg.RasterizerFlags | extra_user_flags; FreetypeLoadFlags = FT_LOAD_NO_BITMAP; if (UserFlags & ImGuiFreeType::NoHinting) FreetypeLoadFlags |= FT_LOAD_NO_HINTING; @@ -146,7 +146,7 @@ namespace return true; } - void FreeTypeFont::Shutdown() + void FreeTypeFont::Destroy() { if (FreetypeFace) { @@ -162,6 +162,7 @@ namespace // I'm not sure how to deal with font sizes properly. // As far as I understand, currently ImGui assumes that the 'pixel_height' is a maximum height of an any given glyph, // i.e. it's the sum of font's ascender and descender. Seems strange to me. + // FT_Set_Pixel_Sizes() doesn't seem to get us the same result. FT_Size_RequestRec req; req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; @@ -180,7 +181,7 @@ namespace Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance); } - bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo &glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap) + bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap) { uint32_t glyph_index = FT_Get_Char_Index(FreetypeFace, codepoint); if (glyph_index == 0) @@ -253,7 +254,8 @@ bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) ImFontAtlasBuildRegisterDefaultCustomRects(atlas); - atlas->TexID = NULL; + // Clear atlas + atlas->TexID = (ImTextureID)NULL; atlas->TexWidth = atlas->TexHeight = 0; atlas->TexUvScale = ImVec2(0.0f, 0.0f); atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); @@ -273,7 +275,7 @@ bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) FreeTypeFont& font_face = fonts[input_i]; IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); - if (!font_face.Init(cfg, extra_flags)) + if (!font_face.Create(cfg, extra_flags)) return false; max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth); @@ -380,7 +382,7 @@ bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) // Cleanup for (int n = 0; n < fonts.Size; n++) - fonts[n].Shutdown(); + fonts[n].Destroy(); ImFontAtlasBuildFinish(atlas); diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index b8062bf7..aa0aba63 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -1,4 +1,4 @@ -// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui +// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype // Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut From e3ccc967895e9bf3986d133224d1e359054849db Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:21:33 +0100 Subject: [PATCH 110/195] Internals: Added ImBoolVector helper. --- imgui_internal.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/imgui_internal.h b/imgui_internal.h index 51f3a3f7..46a37ee2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -236,6 +236,18 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +// Helper: ImBoolVector. Store 1-bit per value. +// Note that Resize() currently clears the whole vector. +struct ImBoolVector +{ + ImVector Storage; + ImBoolVector() { } + void Resize(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (Storage[off] & mask) != 0; } + void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; } +}; + // Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. typedef int ImPoolIdx; From 7cc86d4bc9f5b6a1590201a2381e2b72a7205529 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 18:20:52 +0100 Subject: [PATCH 111/195] Docking: Fixed docking a split node into the empty central node of a dockspace leading to the central node tag being incorrectly carried along. (#2109) --- imgui.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 01899b62..bece4001 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10514,6 +10514,15 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) DockNodeMoveWindows(visible_node, target_node); DockSettingsMoveDockReferencesInInactiveWindow(target_node->ID, visible_node->ID); } + if (target_node->IsCentralNode) + { + // Central node property needs to be moved to a leaf node, pick the last focused one. + ImGuiDockNode* last_focused_node = DockContextFindNodeByID(ctx, payload_node->LastFocusedNodeID); + IM_ASSERT(last_focused_node != NULL && DockNodeGetRootNode(last_focused_node) == DockNodeGetRootNode(payload_node)); + last_focused_node->IsCentralNode = true; + target_node->IsCentralNode = false; + } + IM_ASSERT(target_node->Windows.Size == 0); DockNodeMoveChildNodes(target_node, payload_node); } @@ -10837,7 +10846,7 @@ static void DockNodeUpdateScanRec(ImGuiDockNode* node, ImGuiDockNodeUpdateScanRe if (node->IsCentralNode) { IM_ASSERT(results->CentralNode == NULL); // Should be only one - IM_ASSERT(node->IsLeafNode() && "If you get this assert: your .ini file may have been damaged by an old bug. OR please submit repro of actions leading to this"); + IM_ASSERT(node->IsLeafNode() && "If you get this assert: please submit .ini file + repro of actions leading to this."); results->CentralNode = node; } if (results->CountNodesWithWindows > 1 && results->CentralNode != NULL) From 9a9712807efb4c197d94e9f9a7d2b02159f029d1 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:38:51 +0100 Subject: [PATCH 112/195] ImFontAtlas: Rewrote stb_truetype based builder. - Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth). - Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233) - Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas. --- docs/CHANGELOG.txt | 3 + docs/TODO.txt | 5 +- imgui.h | 2 +- imgui_draw.cpp | 392 +++++++++++++++++++++++++++------------------ imgui_internal.h | 2 +- 5 files changed, 240 insertions(+), 164 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 66ed9545..bd176914 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,9 @@ Other Changes: Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected into e.g. an error log and stopping the script execution. +- ImFontAtlas: Stb: Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth). +- ImFontAtlas: Stb: Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233) +- ImFontAtlas: Stb: Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas. - ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible. (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.) - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. diff --git a/docs/TODO.txt b/docs/TODO.txt index 5e3f73ff..a21bc804 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -235,9 +235,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - pie menus patterns (#434) - markup: simple markup language for color change? (#902) -!- font: need handling of missing glyphs by not packing/rasterizing glyph 0 of a given font. - - font: MergeMode: flags to select overwriting or not. - - font: MergeMode: duplicate glyphs are stored in the atlas texture which is suboptimal. + - font: MergeMode: flags to select overwriting or not (this is now very easy with refactored ImFontAtlasBuildWithStbTruetype) - font: free the Alpha buffer if user only requested RGBA. !- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions). - font: a CalcTextHeight() helper could run faster than CalcTextSize().y @@ -252,7 +250,6 @@ 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: imgui_freetype.h alternative renderer (#618) - 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). - 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) diff --git a/imgui.h b/imgui.h index 9da2e9f2..acc33f2c 100644 --- a/imgui.h +++ b/imgui.h @@ -2047,7 +2047,7 @@ struct ImFontAtlas ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. - int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9833590f..9987b1ab 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1541,11 +1541,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) if (!font_cfg->MergeMode) Fonts.push_back(IM_NEW(ImFont)); else - IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. ConfigData.push_back(*font_cfg); ImFontConfig& new_font_cfg = ConfigData.back(); - if (!new_font_cfg.DstFont) + if (new_font_cfg.DstFont == NULL) new_font_cfg.DstFont = Fonts.back(); if (!new_font_cfg.FontDataOwnedByAtlas) { @@ -1733,139 +1733,220 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig data[i] = table[data[i]]; } +// 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 +{ + stbtt_fontinfo FontInfo; + stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) + stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. + stbtt_packedchar* PackedChars; // Output glyphs + const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) + int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] + int GlyphsHighest; // Highest requested codepoint + int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) + ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap) +}; + +// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) +struct ImFontBuildDstData +{ + int SrcCount; // Number of source fonts targeting this destination font. + int GlyphsHighest; + int GlyphsCount; + ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. +}; + +static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector* out) +{ + IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); + const int* it_begin = in->Storage.begin(); + const int* it_end = in->Storage.end(); + for (const int* it = it_begin; it < it_end; it++) + if (int entries_32 = *it) + for (int bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & (1 << bit_n)) + out->push_back((int)((it - it_begin) << 5) + bit_n); +} + bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { IM_ASSERT(atlas->ConfigData.Size > 0); ImFontAtlasBuildRegisterDefaultCustomRects(atlas); + // Clear atlas atlas->TexID = (ImTextureID)NULL; atlas->TexWidth = atlas->TexHeight = 0; atlas->TexUvScale = ImVec2(0.0f, 0.0f); atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); atlas->ClearTexData(); - // Count glyphs/ranges - int total_glyphs_count = 0; - int total_ranges_count = 0; - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) - { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - if (!cfg.GlyphRanges) - cfg.GlyphRanges = atlas->GetGlyphRangesDefault(); - for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++) - total_glyphs_count += (in_range[1] - in_range[0]) + 1; - } - - // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish. - // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. - atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512; - atlas->TexHeight = 0; - - // Start packing - const int max_tex_height = 1024*32; - stbtt_pack_context spc = {}; - if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL)) - return false; - stbtt_PackSetOversampling(&spc, 1, 1); - - // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). - ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); + // Temporary storage for building + ImVector src_tmp_array; + ImVector dst_tmp_array; + src_tmp_array.resize(atlas->ConfigData.Size); + dst_tmp_array.resize(atlas->Fonts.Size); + memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); + memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); - // Initialize font information (so we can error without any cleanup) - struct ImFontTempBuildData + // 1. Initialize font loading structure, check font data validity + for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) { - stbtt_fontinfo FontInfo; - stbrp_rect* Rects; - int RectsCount; - stbtt_pack_range* Ranges; - int RangesCount; - }; - ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData)); - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) - { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - ImFontTempBuildData& tmp = tmp_array[input_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + src_tmp.DstIndex = -1; + for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) + if (cfg.DstFont == atlas->Fonts[output_i]) + src_tmp.DstIndex = output_i; + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + if (src_tmp.DstIndex == -1) + return false; + + // Initialize helper structure for font loading and verify that the TTF/OTF data is correct const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); - if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) - { - atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure - ImGui::MemFree(tmp_array); + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) return false; - } + + // Measure highest codepoints + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); } + // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. + int total_glyphs_count = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest); + if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) + dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest); + + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + { + if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) + continue; + if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? + continue; + + // Add to avail set/counters + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint, true); + if (dst_tmp.SrcCount > 1) + dst_tmp.GlyphsSet.SetBit(codepoint, true); + total_glyphs_count++; + } + } + + // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); + UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); + src_tmp.GlyphsSet.Clear(); + IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); + } + for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) + dst_tmp_array[dst_i].GlyphsSet.Clear(); + dst_tmp_array.clear(); + // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) - int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0; - stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar)); - stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect)); - stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range)); - memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar)); - memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity. - memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range)); - - // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point) - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) - { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - ImFontTempBuildData& tmp = tmp_array[input_i]; - - // Setup ranges - int font_glyphs_count = 0; - int font_ranges_count = 0; - for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++) - font_glyphs_count += (in_range[1] - in_range[0]) + 1; - tmp.Ranges = buf_ranges + buf_ranges_n; - tmp.RangesCount = font_ranges_count; - buf_ranges_n += font_ranges_count; - for (int i = 0; i < font_ranges_count; i++) - { - const ImWchar* in_range = &cfg.GlyphRanges[i * 2]; - stbtt_pack_range& range = tmp.Ranges[i]; - range.font_size = cfg.SizePixels; - range.first_unicode_codepoint_in_range = in_range[0]; - range.num_chars = (in_range[1] - in_range[0]) + 1; - range.chardata_for_range = buf_packedchars + buf_packedchars_n; - buf_packedchars_n += range.num_chars; - } + // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) + ImVector buf_rects; + ImVector buf_packedchars; + buf_rects.resize(total_glyphs_count); + buf_packedchars.resize(total_glyphs_count); + memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); + memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); + + // 4. Gather glyphs sizes so we can pack them in our virtual canvas. + int total_surface = 0; + int buf_rects_out_n = 0; + int buf_packedchars_out_n = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; - // Gather the sizes of all rectangle we need - tmp.Rects = buf_rects + buf_rects_n; - tmp.RectsCount = font_glyphs_count; - buf_rects_n += font_glyphs_count; - stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV); - int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects); - IM_ASSERT(n == font_glyphs_count); - - // Detect missing glyphs and replace them with a zero-sized box instead of relying on the default glyphs - // This allows us merging overlapping icon fonts more easily. - int rect_i = 0; - for (int range_i = 0; range_i < tmp.RangesCount; range_i++) - for (int char_i = 0; char_i < tmp.Ranges[range_i].num_chars; char_i++, rect_i++) - if (stbtt_FindGlyphIndex(&tmp.FontInfo, tmp.Ranges[range_i].first_unicode_codepoint_in_range + char_i) == 0) - tmp.Rects[rect_i].w = tmp.Rects[rect_i].h = 0; - - // Pack - stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n); - - // Extend texture height - // Also mark missing glyphs as non-packed so we don't attempt to render into them - for (int i = 0; i < n; i++) + src_tmp.Rects = &buf_rects[buf_rects_out_n]; + src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; + buf_rects_out_n += src_tmp.GlyphsCount; + buf_packedchars_out_n += src_tmp.GlyphsCount; + + // Convert our ranges in the format stb_truetype wants + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.PackRange.font_size = cfg.SizePixels; + src_tmp.PackRange.first_unicode_codepoint_in_range = 0; + src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; + src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; + src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; + src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; + src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; + + // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) + const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels); + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) { - if (tmp.Rects[i].w == 0 && tmp.Rects[i].h == 0) - tmp.Rects[i].was_packed = 0; - if (tmp.Rects[i].was_packed) - atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h); + int x0, y0, x1, y1; + const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); + IM_ASSERT(glyph_index_in_font != 0); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); + total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } - IM_ASSERT(buf_rects_n == total_glyphs_count); - IM_ASSERT(buf_packedchars_n == total_glyphs_count); - IM_ASSERT(buf_ranges_n == total_ranges_count); - // Create texture + // We need a width for the skyline algorithm, any width! + // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. + // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. + const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; + atlas->TexHeight = 0; + if (atlas->TexDesiredWidth > 0) + atlas->TexWidth = atlas->TexDesiredWidth; + else + atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512; + + // 5. Start packing + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + const int TEX_HEIGHT_MAX = 1024 * 32; + stbtt_pack_context spc = {}; + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); + ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); + + // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); + + // Extend texture height and mark missing glyphs as non-packed so we won't render them. + // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + if (src_tmp.Rects[glyph_i].was_packed) + atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); + } + + // 7. Allocate texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); @@ -1873,41 +1954,46 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) spc.pixels = atlas->TexPixelsAlpha8; spc.height = atlas->TexHeight; - // Second pass: render font characters - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) + // 8. Render/rasterize font characters into the texture + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - ImFontTempBuildData& tmp = tmp_array[input_i]; - stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV); - stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects); + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); + + // Apply multiply operator if (cfg.RasterizerMultiply != 1.0f) { unsigned char multiply_table[256]; ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); - for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++) + stbrp_rect* r = &src_tmp.Rects[0]; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) if (r->was_packed) - ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes); + ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); } - tmp.Rects = NULL; + src_tmp.Rects = NULL; } // End packing stbtt_PackEnd(&spc); - ImGui::MemFree(buf_rects); - buf_rects = NULL; + buf_rects.clear(); - // Third pass: setup ImFont and glyphs for runtime - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) + // 9. Setup ImFont and glyphs for runtime + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - ImFontTempBuildData& tmp = tmp_array[input_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + ImFontConfig& cfg = atlas->ConfigData[src_i]; ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) - if (cfg.MergeMode) - dst_font->BuildLookupTable(); - const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels); + const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); int unscaled_ascent, unscaled_descent, unscaled_line_gap; - stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); @@ -1915,40 +2001,30 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) const float font_off_x = cfg.GlyphOffset.x; const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f); - for (int i = 0; i < tmp.RangesCount; i++) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) { - stbtt_pack_range& range = tmp.Ranges[i]; - for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1) - { - const stbtt_packedchar& pc = range.chardata_for_range[char_idx]; - if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1) - continue; - - const int codepoint = range.first_unicode_codepoint_in_range + char_idx; - if (cfg.MergeMode && dst_font->FindGlyphNoFallback((ImWchar)codepoint)) - continue; - - float char_advance_x_org = pc.xadvance; - float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); - float char_off_x = font_off_x; - if (char_advance_x_org != char_advance_x_mod) - char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; - - stbtt_aligned_quad q; - float dummy_x = 0.0f, dummy_y = 0.0f; - stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0); - dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod); - } + const int codepoint = src_tmp.GlyphsList[glyph_i]; + const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; + + const float char_advance_x_org = pc.xadvance; + const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); + float char_off_x = font_off_x; + if (char_advance_x_org != char_advance_x_mod) + char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; + + // Register glyph + stbtt_aligned_quad q; + float dummy_x = 0.0f, dummy_y = 0.0f; + stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0); + dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod); } } - // Cleanup temporaries - ImGui::MemFree(buf_packedchars); - ImGui::MemFree(buf_ranges); - ImGui::MemFree(tmp_array); + // Cleanup temporary (ImVector doesn't honor destructor) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + src_tmp_array[src_i].~ImFontBuildSrcData(); ImFontAtlasBuildFinish(atlas); - return true; } @@ -1976,16 +2052,16 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f font->ConfigDataCount++; } -void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque) +void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) { - stbrp_context* pack_context = (stbrp_context*)pack_context_opaque; + stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; ImVector& user_rects = atlas->CustomRects; IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. ImVector pack_rects; pack_rects.resize(user_rects.Size); - memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size); + memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); for (int i = 0; i < user_rects.Size; i++) { pack_rects[i].w = user_rects[i].Width; diff --git a/imgui_internal.h b/imgui_internal.h index 46a37ee2..8b8a299a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1452,7 +1452,7 @@ namespace ImGui IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); -IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); 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); From 21828b08a0f5b4ac70bc66beaf93dcea0279bace Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 22:11:27 +0100 Subject: [PATCH 113/195] ImFontAtlas: Rewrote FreeType based builder. - Fixed abnormally high atlas height. (#618) - Fixed support for any values of TexGlyphPadding (not just only 1). (#618) - Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth). (#618) - Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233, #618) - Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas. (#618) --- docs/CHANGELOG.txt | 8 +- misc/freetype/README.md | 33 +- misc/freetype/imgui_freetype.cpp | 552 +++++++++++++++++++++---------- 3 files changed, 399 insertions(+), 194 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bd176914..048f176f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,9 +72,11 @@ Other Changes: Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected into e.g. an error log and stopping the script execution. -- ImFontAtlas: Stb: Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth). -- ImFontAtlas: Stb: Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233) -- ImFontAtlas: Stb: Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas. +- ImFontAtlas: Stb and FreeType: Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth). +- ImFontAtlas: Stb and FreeType: Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233) +- ImFontAtlas: Stb and FreeType: Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas. +- ImFontAtlas: FreeType: Fixed abnormally high atlas height. +- ImFontAtlas: FreeType: Fixed support for any values of TexGlyphPadding (not just only 1). - ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible. (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.) - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. diff --git a/misc/freetype/README.md b/misc/freetype/README.md index ba633f69..885451a4 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -1,14 +1,14 @@ # imgui_freetype -This is an attempt to replace stb_truetype (the default imgui's font rasterizer) with FreeType. -Currently not optimal and probably has some limitations or bugs. -By [Vuhdo](https://github.com/Vuhdo) (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut. +Build font atlases using FreeType instead of stb_truetype (the default imgui's font rasterizer). +
by @vuhdo, @mikesart, @ocornut. -**Usage** -1. Get latest FreeType binaries or build yourself. +### Usage + +1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype`). 2. Add imgui_freetype.h/cpp alongside your imgui sources. 3. Include imgui_freetype.h after imgui.h. -4. Call ImGuiFreeType::BuildFontAtlas() *BEFORE* calling ImFontAtlas::GetTexDataAsRGBA32() or ImFontAtlas::Build() (so normal Build() won't be called): +4. Call `ImGuiFreeType::BuildFontAtlas()` *BEFORE* calling `ImFontAtlas::GetTexDataAsRGBA32()` or `ImFontAtlas::Build()` (so normal Build() won't be called): ```cpp // See ImGuiFreeType::RasterizationFlags @@ -17,13 +17,14 @@ ImGuiFreeType::BuildFontAtlas(io.Fonts, flags); io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); ``` -**Gamma Correct Blending** +### Gamma Correct Blending + FreeType assumes blending in linear space rather than gamma space. See FreeType note for [FT_Render_Glyph](https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph). For correct results you need to be using sRGB and convert to linear space in the pixel shader output. The default imgui styles will be impacted by this change (alpha values will need tweaking). -**Test code Usage** +### Test code Usage ```cpp #include "misc/freetype/imgui_freetype.h" #include "misc/freetype/imgui_freetype.cpp" @@ -42,16 +43,15 @@ while (true) if (freetype_test.UpdateRebuild()) { // REUPLOAD FONT TEXTURE TO GPU - // e.g ImGui_ImplGlfwGL3_InvalidateDeviceObjects() + ImGui_ImplGlfwGL3_CreateDeviceObjects() + // e.g ImGui_ImplOpenGL3_DestroyDeviceObjects() + ImGui_ImplOpenGL3_CreateDeviceObjects() } ImGui::NewFrame(); freetype_test.ShowFreetypeOptionsWindow(); ... - } } ``` -**Test code** +### Test code ```cpp #include "misc/freetype/imgui_freetype.h" #include "misc/freetype/imgui_freetype.cpp" @@ -61,7 +61,7 @@ struct FreeTypeTest enum FontBuildMode { FontBuildMode_FreeType, - FontBuildMode_Stb, + FontBuildMode_Stb }; FontBuildMode BuildMode; @@ -120,14 +120,7 @@ struct FreeTypeTest }; ``` -**Known issues** -- Output texture has excessive resolution (lots of vertical waste). +### Known issues - FreeType's memory allocator is not overridden. - `cfg.OversampleH`, `OversampleV` are ignored (but perhaps not so necessary with this rasterizer). -**Obligatory comparison screenshots** - -Using Windows built-in segoeui.ttf font. Open in new browser tabs, view at 1080p+. - -![freetype rasterizer](https://raw.githubusercontent.com/wiki/ocornut/imgui_club/images/freetype_20170817.png) - diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 70039491..263dd938 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -1,6 +1,6 @@ // Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui // Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype -// Original code by @Vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut +// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained and v0.60+ by @ocornut. // Changelog: // - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks. @@ -10,6 +10,7 @@ // - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member // - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club) // - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX +// - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding. // Gamma Correct Blending: // FreeType assumes blending in linear space rather than gamma space. @@ -17,13 +18,11 @@ // For correct results you need to be using sRGB and convert to linear space in the pixel shader output. // The default imgui styles will be impacted by this change (alpha values will need tweaking). -// TODO: -// - Output texture has excessive resolution (lots of vertical waste). -// - FreeType's memory allocator is not overridden. -// - cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). +// FIXME: FreeType's memory allocator is not overridden. +// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). #include "imgui_freetype.h" -#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*, +#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*, #include #include #include FT_FREETYPE_H // @@ -74,15 +73,15 @@ namespace /// A structure that describe a glyph. struct GlyphInfo { - float Width; // Glyph's width in pixels. - float Height; // Glyph's height in pixels. - float OffsetX; // The distance from the origin ("pen position") to the left of the glyph. - float OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0. - float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0. + int Width; // Glyph's width in pixels. + int Height; // Glyph's height in pixels. + FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph. + FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0. + float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0. }; // Font parameters and metrics. - struct FontInfo + struct FontInfo { uint32_t PixelHeight; // Size this font was generated with. float Ascender; // The pixel extents above the baseline in pixels (typically positive). @@ -96,34 +95,31 @@ namespace // NB: No ctor/dtor, explicitly call Init()/Shutdown() struct FreeTypeFont { - bool Create(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. - void Destroy(); - void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size - - bool CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap); - void BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL); + bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + void CloseFont(); + void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size + const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint, uint32_t* out_glyph_index); + const FT_Bitmap* RenderGlyphAndGetInfo(uint32_t in_glyph_index, GlyphInfo* out_glyph_info); + void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL); + ~FreeTypeFont() { CloseFont(); } // [Internals] FontInfo Info; // Font descriptor of the current font. + FT_Face Face; unsigned int UserFlags; // = ImFontConfig::RasterizerFlags - FT_Library FreetypeLibrary; - FT_Face FreetypeFace; - FT_Int32 FreetypeLoadFlags; + FT_Int32 LoadFlags; }; // From SDL_ttf: Handy routines for converting from fixed point #define FT_CEIL(X) (((X + 63) & -64) / 64) - bool FreeTypeFont::Create(const ImFontConfig& cfg, unsigned int extra_user_flags) + bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags) { // FIXME: substitute allocator - FT_Error error = FT_Init_FreeType(&FreetypeLibrary); - if (error != 0) - return false; - error = FT_New_Memory_Face(FreetypeLibrary, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &FreetypeFace); + FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); if (error != 0) return false; - error = FT_Select_Charmap(FreetypeFace, FT_ENCODING_UNICODE); + error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE); if (error != 0) return false; @@ -132,47 +128,47 @@ namespace // Convert to FreeType flags (NB: Bold and Oblique are processed separately) UserFlags = cfg.RasterizerFlags | extra_user_flags; - FreetypeLoadFlags = FT_LOAD_NO_BITMAP; - if (UserFlags & ImGuiFreeType::NoHinting) FreetypeLoadFlags |= FT_LOAD_NO_HINTING; - if (UserFlags & ImGuiFreeType::NoAutoHint) FreetypeLoadFlags |= FT_LOAD_NO_AUTOHINT; - if (UserFlags & ImGuiFreeType::ForceAutoHint) FreetypeLoadFlags |= FT_LOAD_FORCE_AUTOHINT; - if (UserFlags & ImGuiFreeType::LightHinting) - FreetypeLoadFlags |= FT_LOAD_TARGET_LIGHT; - else if (UserFlags & ImGuiFreeType::MonoHinting) - FreetypeLoadFlags |= FT_LOAD_TARGET_MONO; + LoadFlags = FT_LOAD_NO_BITMAP; + if (UserFlags & ImGuiFreeType::NoHinting) + LoadFlags |= FT_LOAD_NO_HINTING; + if (UserFlags & ImGuiFreeType::NoAutoHint) + LoadFlags |= FT_LOAD_NO_AUTOHINT; + if (UserFlags & ImGuiFreeType::ForceAutoHint) + LoadFlags |= FT_LOAD_FORCE_AUTOHINT; + if (UserFlags & ImGuiFreeType::LightHinting) + LoadFlags |= FT_LOAD_TARGET_LIGHT; + else if (UserFlags & ImGuiFreeType::MonoHinting) + LoadFlags |= FT_LOAD_TARGET_MONO; else - FreetypeLoadFlags |= FT_LOAD_TARGET_NORMAL; + LoadFlags |= FT_LOAD_TARGET_NORMAL; return true; } - void FreeTypeFont::Destroy() + void FreeTypeFont::CloseFont() { - if (FreetypeFace) + if (Face) { - FT_Done_Face(FreetypeFace); - FreetypeFace = NULL; - FT_Done_FreeType(FreetypeLibrary); - FreetypeLibrary = NULL; + FT_Done_Face(Face); + Face = NULL; } } void FreeTypeFont::SetPixelHeight(int pixel_height) { - // I'm not sure how to deal with font sizes properly. - // As far as I understand, currently ImGui assumes that the 'pixel_height' is a maximum height of an any given glyph, - // i.e. it's the sum of font's ascender and descender. Seems strange to me. - // FT_Set_Pixel_Sizes() doesn't seem to get us the same result. + // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' + // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. + // NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result. FT_Size_RequestRec req; req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; req.height = (uint32_t)pixel_height * 64; req.horiResolution = 0; req.vertResolution = 0; - FT_Request_Size(FreetypeFace, &req); + FT_Request_Size(Face, &req); - // update font info - FT_Size_Metrics metrics = FreetypeFace->size->metrics; + // Update font info + FT_Size_Metrics metrics = Face->size->metrics; Info.PixelHeight = (uint32_t)pixel_height; Info.Ascender = (float)FT_CEIL(metrics.ascender); Info.Descender = (float)FT_CEIL(metrics.descender); @@ -181,52 +177,77 @@ namespace Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance); } - bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap) + const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint, uint32_t* out_glyph_index) { - uint32_t glyph_index = FT_Get_Char_Index(FreetypeFace, codepoint); + if (out_glyph_index) + *out_glyph_index = 0; + + uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint); if (glyph_index == 0) - return false; - FT_Error error = FT_Load_Glyph(FreetypeFace, glyph_index, FreetypeLoadFlags); + return NULL; + FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags); if (error) - return false; + return NULL; + + if (out_glyph_index) + *out_glyph_index = glyph_index; // Need an outline for this to work - FT_GlyphSlot slot = FreetypeFace->glyph; + FT_GlyphSlot slot = Face->glyph; IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE); + // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) if (UserFlags & ImGuiFreeType::Bold) FT_GlyphSlot_Embolden(slot); if (UserFlags & ImGuiFreeType::Oblique) + { FT_GlyphSlot_Oblique(slot); + //FT_BBox bbox; + //FT_Outline_Get_BBox(&slot->outline, &bbox); + //slot->metrics.width = bbox.xMax - bbox.xMin; + //slot->metrics.height = bbox.yMax - bbox.yMin; + } - // Retrieve the glyph - error = FT_Get_Glyph(slot, &ft_glyph); - if (error != 0) - return false; + return &slot->metrics; + } + + const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(uint32_t in_glyph_index, GlyphInfo* out_glyph_info) + { + IM_ASSERT(in_glyph_index != 0); + FT_Error error = FT_Load_Glyph(Face, in_glyph_index, LoadFlags); + if (error) + return NULL; + + // Need an outline for this to work + FT_GlyphSlot slot = Face->glyph; + IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE); + + if (UserFlags & ImGuiFreeType::Bold) + FT_GlyphSlot_Embolden(slot); + if (UserFlags & ImGuiFreeType::Oblique) + FT_GlyphSlot_Oblique(slot); - // Rasterize - error = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, NULL, true); + error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); if (error != 0) return false; - ft_bitmap = (FT_BitmapGlyph)ft_glyph; - glyph_info.AdvanceX = (float)FT_CEIL(slot->advance.x); - glyph_info.OffsetX = (float)ft_bitmap->left; - glyph_info.OffsetY = -(float)ft_bitmap->top; - glyph_info.Width = (float)ft_bitmap->bitmap.width; - glyph_info.Height = (float)ft_bitmap->bitmap.rows; + FT_Bitmap* ft_bitmap = &Face->glyph->bitmap; + out_glyph_info->Width = (int)ft_bitmap->width; + out_glyph_info->Height = (int)ft_bitmap->rows; + out_glyph_info->OffsetX = Face->glyph->bitmap_left; + out_glyph_info->OffsetY = -Face->glyph->bitmap_top; + out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x); - return true; + return ft_bitmap; } - void FreeTypeFont::BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) + void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) { IM_ASSERT(ft_bitmap != NULL); - - const uint32_t w = ft_bitmap->bitmap.width; - const uint32_t h = ft_bitmap->bitmap.rows; - const uint8_t* src = ft_bitmap->bitmap.buffer; - const uint32_t src_pitch = ft_bitmap->bitmap.pitch; + const uint32_t w = ft_bitmap->width; + const uint32_t h = ft_bitmap->rows; + const uint8_t* src = ft_bitmap->buffer; + const uint32_t src_pitch = ft_bitmap->pitch; if (multiply_table == NULL) { @@ -247,10 +268,38 @@ namespace #define STB_RECT_PACK_IMPLEMENTATION #include "imstb_rectpack.h" -bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) +struct ImFontBuildSrcGlyphFT +{ + GlyphInfo Info; + uint32_t Codepoint; + uint32_t GlyphIndex; // Index in font (to avoid calling FT_Get_Char_Index multiple times) + unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array +}; + +struct ImFontBuildSrcDataFT +{ + FreeTypeFont Font; + stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. + const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) + int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] + int GlyphsHighest; // Highest requested codepoint + int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) + ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; +}; + +// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) +struct ImFontBuildDstDataFT +{ + int SrcCount; // Number of source fonts targeting this destination font. + int GlyphsHighest; + int GlyphsCount; + ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. +}; + +bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags) { IM_ASSERT(atlas->ConfigData.Size > 0); - IM_ASSERT(atlas->TexGlyphPadding == 1); // Not supported ImFontAtlasBuildRegisterDefaultCustomRects(atlas); @@ -261,130 +310,291 @@ bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); atlas->ClearTexData(); - ImVector fonts; - fonts.resize(atlas->ConfigData.Size); - - ImVec2 max_glyph_size(1.0f, 1.0f); + // Temporary storage for building + ImVector src_tmp_array; + ImVector dst_tmp_array; + src_tmp_array.resize(atlas->ConfigData.Size); + dst_tmp_array.resize(atlas->Fonts.Size); + memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); + memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); - // Count glyphs/ranges, initialize font - int total_glyphs_count = 0; - int total_ranges_count = 0; - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) + // 1. Initialize font loading structure, check font data validity + for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - FreeTypeFont& font_face = fonts[input_i]; + ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + FreeTypeFont& font_face = src_tmp.Font; IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); - if (!font_face.Create(cfg, extra_flags)) + // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + src_tmp.DstIndex = -1; + for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) + if (cfg.DstFont == atlas->Fonts[output_i]) + src_tmp.DstIndex = output_i; + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + if (src_tmp.DstIndex == -1) + return false; + + // Load font + if (!font_face.InitFont(ft_library, cfg, extra_flags)) return false; - max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth); - max_glyph_size.y = ImMax(max_glyph_size.y, font_face.Info.Ascender - font_face.Info.Descender); + // Measure highest codepoints + ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); + } + + // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. + int total_glyphs_count = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest); + if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) + dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest); + + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + { + if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) + continue; + uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..) + if (glyph_index == 0) + continue; + + // Add to avail set/counters + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint, true); + if (dst_tmp.SrcCount > 1) + dst_tmp.GlyphsSet.SetBit(codepoint, true); + total_glyphs_count++; + } + } + + // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); + + IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(int)); + const int* it_begin = src_tmp.GlyphsSet.Storage.begin(); + const int* it_end = src_tmp.GlyphsSet.Storage.end(); + for (const int* it = it_begin; it < it_end; it++) + if (int entries_32 = *it) + for (int bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & (1 << bit_n)) + { + ImFontBuildSrcGlyphFT src_glyph; + memset(&src_glyph, 0, sizeof(src_glyph)); + src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n); + //src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it.. + src_tmp.GlyphsList.push_back(src_glyph); + } + src_tmp.GlyphsSet.Clear(); + IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); + } + for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) + dst_tmp_array[dst_i].GlyphsSet.Clear(); + dst_tmp_array.clear(); + + // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) + // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) + ImVector buf_rects; + buf_rects.resize(total_glyphs_count); + memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); + + // Allocate temporary rasterization data buffers. + // We could not find a way to retrieve accurate glyph size without rendering them. + // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform) + // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations. + const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024; + int buf_bitmap_current_used_bytes = 0; + ImVector buf_bitmap_buffers; + buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE)); + + // 4. Gather glyphs sizes so we can pack them in our virtual canvas. + // 8. Render/rasterize font characters into the texture + int total_surface = 0; + int buf_rects_out_n = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + src_tmp.Rects = &buf_rects[buf_rects_out_n]; + buf_rects_out_n += src_tmp.GlyphsCount; + + // Compute multiply table if requested + const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f); + unsigned char multiply_table[256]; + if (multiply_enabled) + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + + // Gather the sizes of all rectangles we will need to pack + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) + { + ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; + + const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint, &src_glyph.GlyphIndex); + IM_ASSERT(metrics != NULL); + if (metrics == NULL) + continue; - if (!cfg.GlyphRanges) - cfg.GlyphRanges = atlas->GetGlyphRangesDefault(); - for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[ 1 ]; in_range += 2, total_ranges_count++) - total_glyphs_count += (in_range[1] - in_range[0]) + 1; + // Render glyph into a bitmap (currently held by FreeType) + const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(src_glyph.GlyphIndex, &src_glyph.Info); + IM_ASSERT(ft_bitmap); + + // Allocate new temporary chunk if needed + const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height; + if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE) + { + buf_bitmap_current_used_bytes = 0; + buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE)); + } + + // Blit rasterized pixels to our temporary buffer and keep a pointer to it. + src_glyph.BitmapData = buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes; + buf_bitmap_current_used_bytes += bitmap_size_in_bytes; + src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width * 1, multiply_enabled ? multiply_table : NULL); + + src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding); + total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; + } } - // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish. - // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. - atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512; + // We need a width for the skyline algorithm, any width! + // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. + // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. + const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; + atlas->TexHeight = 0; + if (atlas->TexDesiredWidth > 0) + atlas->TexWidth = atlas->TexDesiredWidth; + else + atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512; + + // 5. Start packing + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + const int TEX_HEIGHT_MAX = 1024 * 32; + const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding; + ImVector pack_nodes; + pack_nodes.resize(num_nodes_for_packing_algorithm); + stbrp_context pack_context; + stbrp_init_target(&pack_context, atlas->TexWidth, TEX_HEIGHT_MAX, pack_nodes.Data, pack_nodes.Size); + ImFontAtlasBuildPackCustomRects(atlas, &pack_context); - // We don't do the original first pass to determine texture height, but just rough estimate. - // Looks ugly inaccurate and excessive, but AFAIK with FreeType we actually need to render glyphs to get exact sizes. - // Alternatively, we could just render all glyphs into a big shadow buffer, get their sizes, do the rectangle packing and just copy back from the - // shadow buffer to the texture buffer. Will give us an accurate texture height, but eat a lot of temp memory. Probably no one will notice.) - const int total_rects = total_glyphs_count + atlas->CustomRects.size(); - float min_rects_per_row = ceilf((atlas->TexWidth / (max_glyph_size.x + 1.0f))); - float min_rects_per_column = ceilf(total_rects / min_rects_per_row); - atlas->TexHeight = (int)(min_rects_per_column * (max_glyph_size.y + 1.0f)); + // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; - // Create texture + stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount); + + // Extend texture height and mark missing glyphs as non-packed so we won't render them. + // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + if (src_tmp.Rects[glyph_i].was_packed) + atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); + } + + // 7. Allocate texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); - // Start packing - ImVector pack_nodes; - pack_nodes.resize(total_rects); - stbrp_context context; - stbrp_init_target(&context, atlas->TexWidth, atlas->TexHeight, pack_nodes.Data, total_rects); + // 8. Copy rasterized font characters back into the main texture + // 9. Setup ImFont and glyphs for runtime + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; - // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). - ImFontAtlasBuildPackCustomRects(atlas, &context); + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) - // Render characters, setup ImFont and glyphs for runtime - for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) - { - ImFontConfig& cfg = atlas->ConfigData[input_i]; - FreeTypeFont& font_face = fonts[input_i]; - ImFont* dst_font = cfg.DstFont; - if (cfg.MergeMode) - dst_font->BuildLookupTable(); - - const float ascent = font_face.Info.Ascender; - const float descent = font_face.Info.Descender; + const float ascent = src_tmp.Font.Info.Ascender; + const float descent = src_tmp.Font.Info.Descender; ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); const float font_off_x = cfg.GlyphOffset.x; const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f); - bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f); - unsigned char multiply_table[256]; - if (multiply_enabled) - ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); - - for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2) + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) { - for (uint32_t codepoint = in_range[0]; codepoint <= in_range[1]; ++codepoint) - { - if (cfg.MergeMode && dst_font->FindGlyphNoFallback((ImWchar)codepoint)) - continue; - - FT_Glyph ft_glyph = NULL; - FT_BitmapGlyph ft_glyph_bitmap = NULL; // NB: will point to bitmap within FT_Glyph - GlyphInfo glyph_info; - if (!font_face.CalcGlyphInfo(codepoint, glyph_info, ft_glyph, ft_glyph_bitmap)) - continue; - - // Pack rectangle - stbrp_rect rect; - rect.w = (uint16_t)glyph_info.Width + 1; // Account for texture filtering - rect.h = (uint16_t)glyph_info.Height + 1; - stbrp_pack_rects(&context, &rect, 1); - - // Copy rasterized pixels to main texture - uint8_t* blit_dst = atlas->TexPixelsAlpha8 + rect.y * atlas->TexWidth + rect.x; - font_face.BlitGlyph(ft_glyph_bitmap, blit_dst, atlas->TexWidth, multiply_enabled ? multiply_table : NULL); - FT_Done_Glyph(ft_glyph); - - float char_advance_x_org = glyph_info.AdvanceX; - float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); - float char_off_x = font_off_x; - if (char_advance_x_org != char_advance_x_mod) - char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; - - // Register glyph - dst_font->AddGlyph((ImWchar)codepoint, - glyph_info.OffsetX + char_off_x, - glyph_info.OffsetY + font_off_y, - glyph_info.OffsetX + char_off_x + glyph_info.Width, - glyph_info.OffsetY + font_off_y + glyph_info.Height, - rect.x / (float)atlas->TexWidth, - rect.y / (float)atlas->TexHeight, - (rect.x + glyph_info.Width) / (float)atlas->TexWidth, - (rect.y + glyph_info.Height) / (float)atlas->TexHeight, - char_advance_x_mod); - } + ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; + stbrp_rect& pack_rect = src_tmp.Rects[glyph_i]; + IM_ASSERT(pack_rect.was_packed); + + GlyphInfo& info = src_glyph.Info; + IM_ASSERT(info.Width + padding <= pack_rect.w); + IM_ASSERT(info.Height + padding <= pack_rect.h); + const int tx = pack_rect.x + padding; + const int ty = pack_rect.y + padding; + + // Blit from temporary buffer to final texture + size_t blit_src_stride = (size_t)src_glyph.Info.Width; + size_t blit_dst_stride = (size_t)atlas->TexWidth; + unsigned char* blit_src = src_glyph.BitmapData; + unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx; + for (int y = info.Height; y > 0; y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride) + memcpy(blit_dst, blit_src, blit_src_stride); + + float char_advance_x_org = info.AdvanceX; + float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); + float char_off_x = font_off_x; + if (char_advance_x_org != char_advance_x_mod) + char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; + + // Register glyph + float x0 = info.OffsetX + char_off_x; + float y0 = info.OffsetY + font_off_y; + float x1 = x0 + info.Width; + float y1 = y0 + info.Height; + float u0 = (tx) / (float)atlas->TexWidth; + float v0 = (ty) / (float)atlas->TexHeight; + float u1 = (tx + info.Width) / (float)atlas->TexWidth; + float v1 = (ty + info.Height) / (float)atlas->TexHeight; + dst_font->AddGlyph((ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, char_advance_x_mod); } + + src_tmp.Rects = NULL; } // Cleanup - for (int n = 0; n < fonts.Size; n++) - fonts[n].Destroy(); + for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++) + ImGui::MemFree(buf_bitmap_buffers[buf_i]); + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + src_tmp_array[src_i].~ImFontBuildSrcDataFT(); ImFontAtlasBuildFinish(atlas); return true; } + +bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) +{ + FT_Library ft_library; + FT_Error error = FT_Init_FreeType(&ft_library); + if (error != 0) + return false; + + bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags); + FT_Done_FreeType(ft_library); + + return ret; +} From 651130002f4fc13c24f1bddb3e007fb789c5a0a2 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 11 Jan 2019 15:25:43 +0100 Subject: [PATCH 114/195] ImFontAtlas: Fixed allocating for last bit (would only affect is that last codepoint is a multiple of 32). (#2270) --- imgui_draw.cpp | 4 ++-- misc/freetype/imgui_freetype.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9987b1ab..4ea37353 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1829,9 +1829,9 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; ImFontConfig& cfg = atlas->ConfigData[src_i]; - src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest); + src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) - dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest); + dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 263dd938..33a5a63b 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -355,9 +355,9 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; ImFontConfig& cfg = atlas->ConfigData[src_i]; - src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest); + src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) - dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest); + dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) From 8df8482ef4011b8ead449dfe65db0632e759f9f3 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 12 Jan 2019 11:45:58 +0100 Subject: [PATCH 115/195] imgui_freetype: Fixed redundant FT_Load_Glyph() calls, unused parameters, and compilation warning/error. (#2270) --- misc/freetype/imgui_freetype.cpp | 36 +++++++------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 33a5a63b..7c5403b6 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -98,8 +98,8 @@ namespace bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. void CloseFont(); void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size - const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint, uint32_t* out_glyph_index); - const FT_Bitmap* RenderGlyphAndGetInfo(uint32_t in_glyph_index, GlyphInfo* out_glyph_info); + const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); + const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL); ~FreeTypeFont() { CloseFont(); } @@ -177,11 +177,8 @@ namespace Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance); } - const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint, uint32_t* out_glyph_index) + const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint) { - if (out_glyph_index) - *out_glyph_index = 0; - uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint); if (glyph_index == 0) return NULL; @@ -189,9 +186,6 @@ namespace if (error) return NULL; - if (out_glyph_index) - *out_glyph_index = glyph_index; - // Need an outline for this to work FT_GlyphSlot slot = Face->glyph; IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE); @@ -211,25 +205,12 @@ namespace return &slot->metrics; } - const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(uint32_t in_glyph_index, GlyphInfo* out_glyph_info) + const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) { - IM_ASSERT(in_glyph_index != 0); - FT_Error error = FT_Load_Glyph(Face, in_glyph_index, LoadFlags); - if (error) - return NULL; - - // Need an outline for this to work FT_GlyphSlot slot = Face->glyph; - IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE); - - if (UserFlags & ImGuiFreeType::Bold) - FT_GlyphSlot_Embolden(slot); - if (UserFlags & ImGuiFreeType::Oblique) - FT_GlyphSlot_Oblique(slot); - - error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); + FT_Error error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); if (error != 0) - return false; + return NULL; FT_Bitmap* ft_bitmap = &Face->glyph->bitmap; out_glyph_info->Width = (int)ft_bitmap->width; @@ -272,7 +253,6 @@ struct ImFontBuildSrcGlyphFT { GlyphInfo Info; uint32_t Codepoint; - uint32_t GlyphIndex; // Index in font (to avoid calling FT_Get_Char_Index multiple times) unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array }; @@ -446,13 +426,13 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns { ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; - const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint, &src_glyph.GlyphIndex); + const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint); IM_ASSERT(metrics != NULL); if (metrics == NULL) continue; // Render glyph into a bitmap (currently held by FreeType) - const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(src_glyph.GlyphIndex, &src_glyph.Info); + const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info); IM_ASSERT(ft_bitmap); // Allocate new temporary chunk if needed From 49994ceb6edee01a25a25c4c304038a60cf0eb74 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 11 Jan 2019 17:38:14 +0100 Subject: [PATCH 116/195] FAQ entry, moved ImTextureId, Gallery links. --- docs/README.md | 8 +++++--- docs/TODO.txt | 1 + imgui.cpp | 23 +++++++++++++++++++++++ imgui.h | 6 +++--- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5f9a188c..b1e10d53 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,7 +20,7 @@ Dear ImGui is designed to enable fast iterations and to empower programmers to c Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard. -See [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui), [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Gallery](https://github.com/ocornut/imgui/issues/1902) pages to get an idea of its use cases. +See [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui), [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Gallery](https://github.com/ocornut/imgui/issues/2265) pages to get an idea of its use cases. Dear ImGui is self-contained within a few files that you can easily copy and compile into your application/engine: - imgui.cpp @@ -175,7 +175,8 @@ User screenshots:
[Gallery Part 4](https://github.com/ocornut/imgui/issues/973) (Jan 2017 to Aug 2017)
[Gallery Part 5](https://github.com/ocornut/imgui/issues/1269) (Aug 2017 to Feb 2018)
[Gallery Part 6](https://github.com/ocornut/imgui/issues/1607) (Feb 2018 to June 2018) -
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 onward) +
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 to January 2018) +
[Gallery Part 8](https://github.com/ocornut/imgui/issues/2265) (January 2018 onward)
Also see the [Mega screenshots](https://github.com/ocornut/imgui/issues/1273) for an idea of the available features. Custom engine @@ -243,6 +244,7 @@ The library started its life and is best known as "ImGui" only due to the fact t
**How can I easily use icons in my application?**
**How can I load multiple fonts?**
**How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?** ([example](https://github.com/ocornut/imgui/wiki/Loading-Font-Example)) +
**How can I interact with standard C++ types (such as std::string and std::vector)?**
**How can I use the drawing facilities without an Dear ImGui window? (using ImDrawList API)**
**How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)**
**I integrated Dear ImGui in my engine and the text or lines are blurry..** @@ -298,7 +300,7 @@ Ongoing dear imgui development is financially supported by users and private spo - **Blizzard Entertainment**. **Double-chocolate sponsors** -- Media Molecule, Mobigame, Insomniac Games, Aras Pranckevičius, Lizardcube, Greggman, DotEmu, Nadeo, Supercell, Runner, Aiden Koss. +- Media Molecule, Mobigame, Insomniac Games, Aras Pranckevičius, Lizardcube, Greggman, DotEmu, Nadeo, Supercell, Runner, Aiden Koss, Kylotonn. **Salty caramel supporters** - Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Recognition Robotics, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko, Mercury Labs, Singularity Demo Group, Mischa Alff, Sebastien Ronsse, Lionel Landwerlin, Nikolay Ivanov, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts, Rainway inc. diff --git a/docs/TODO.txt b/docs/TODO.txt index 5e3f73ff..9c5f3140 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -257,6 +257,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - 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) - font: fix AddRemapChar() to work before font has been built. + - font: what would it take to support codepoint higher than 0xFFFF? (smileys, etc.) - font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF. - font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer? - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16 bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? diff --git a/imgui.cpp b/imgui.cpp index c9b4188b..8c118918 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -45,6 +45,7 @@ DOCUMENTATION - How can I easily use icons in my application? - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? + - How can I interact with standard C++ types (such as std::string and std::vector)? - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad) - I integrated Dear ImGui in my engine and the text or lines are blurry.. @@ -843,6 +844,28 @@ CODE Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly. + Q: How can I interact with standard C++ types (such as std::string and std::vector)? + A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers), + and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use + any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases. + - To use ImGui::InputText() with a std::string or any resizable string class, see misc/cpp/imgui_stdlib.h. + - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API + lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API. + Prefer using them over the old and awkward Combo()/ListBox() api. + - Generally for most high-level types you should be able to access the underlying data type. + You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code). + - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass + to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application. + Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances. + Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those + are not configurable and not the same across implementations. + - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount + of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern + is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead. + One possible implementation of a helper to facilitate printf-style building of strings: https://github.com/ocornut/Str + This is a small helper where you can instance strings with configurable local buffers length. Many game engines will + provide similar or better string helpers. + Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) A: - You can create a dummy window. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags. (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse) diff --git a/imgui.h b/imgui.h index dad97c6f..3ac1f0e9 100644 --- a/imgui.h +++ b/imgui.h @@ -98,9 +98,6 @@ struct ImFontConfig; // Configuration data when adding a font or struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) -#ifndef ImTextureID -typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) -#endif struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) struct ImGuiIO; // Main configuration and I/O between your application and ImGui struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) @@ -115,6 +112,9 @@ struct ImGuiTextFilter; // Helper to parse and apply text filters (e // Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +#ifndef ImTextureID +typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) +#endif typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings. typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling From 7e78865613cc0159d4705997a0d19967eb2767d0 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 12 Jan 2019 19:46:35 +0100 Subject: [PATCH 117/195] Demo: Fixed bounds of DragFloat in Clipping section to avoid passing zero-sized to InvisibleButton(). --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index dcaa3660..cf1d4b38 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1988,7 +1988,7 @@ static void ShowDemoWindowLayout() { static ImVec2 size(100, 100), offset(50, 20); ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); - ImGui::DragFloat2("size", (float*)&size, 0.5f, 0.0f, 200.0f, "%.0f"); + ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); ImGui::TextWrapped("(Click and drag)"); ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); From 6e41745f313d7122cc70e7e09f443f1776d8616a Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 13 Jan 2019 18:57:46 +0100 Subject: [PATCH 118/195] Added a bunch of diagnostic ignore to cope with Clang -Weverything being absurd. Also fixed two legit warnings. (#2277) --- imgui.cpp | 6 +++++- imgui.h | 3 ++- imgui_demo.cpp | 4 ++++ imgui_draw.cpp | 3 ++- imgui_internal.h | 8 ++++++-- imgui_widgets.cpp | 6 ++++++ 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8c118918..5a13076a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -955,7 +955,11 @@ CODE #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // #pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. -#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size diff --git a/imgui.h b/imgui.h index 61280a4d..d1be69d0 100644 --- a/imgui.h +++ b/imgui.h @@ -77,6 +77,7 @@ Index of this file: #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #elif defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" @@ -447,7 +448,7 @@ namespace ImGui IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); - IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index cf1d4b38..20a1434d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -70,6 +70,10 @@ Index of this file: #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif #if __has_warning("-Wreserved-id-macro") #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // #endif diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4ea37353..4b9639c7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -57,6 +57,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 #if __has_warning("-Wcomma") #pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // #endif @@ -64,7 +65,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // #endif #if __has_warning("-Wdouble-promotion") -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #endif #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used diff --git a/imgui_internal.h b/imgui_internal.h index 8b8a299a..fad2c1bb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -43,9 +43,13 @@ Index of this file: #ifdef __clang__ #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h -#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h #pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" +#endif #endif //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d65a420b..6f5836d8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -52,8 +52,14 @@ Index of this file: // Clang/GCC warnings with -Weverything #ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked #if __GNUC__ >= 8 From 1da40df279bc8eb33f68664d5aaa835af542e7fc Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 14 Jan 2019 17:37:48 +0100 Subject: [PATCH 119/195] DragFloat: Fixed broken mouse direction change with power!=1.0. (#2174, #2206) [@Joshhua5] --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 048f176f..f97de110 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,7 @@ Other Changes: - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected in the parent window, so there is no mismatch between the layout in parent and the position of the child window. - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) +- DragFloat: Fixed broken mouse direction change with power!=1.0. (#2174, #2206) [@Joshhua5] - Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary keep the focus on the parent window, which could steal it from newly appearing windows. (#787) - Nav: Fixed animated window titles from being updated when displayed in the CTRL+Tab list. (#787) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6f5836d8..b14db7e3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1727,6 +1727,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool has_min_max = (v_min != v_max); + const bool is_power = (power != 1.0f && is_decimal && has_min_max && (v_max - v_min < FLT_MAX)); // Default tweak speed if (v_speed == 0.0f && has_min_max && (v_max - v_min < FLT_MAX)) @@ -1758,7 +1759,8 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. bool is_just_activated = g.ActiveIdIsJustActivated; bool is_already_past_limits_and_pushing_outward = has_min_max && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); - if (is_just_activated || is_already_past_limits_and_pushing_outward) + bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0)); + if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power) { g.DragCurrentAccum = 0.0f; g.DragCurrentAccumDirty = false; @@ -1775,7 +1777,6 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_cur = *v; FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; - const bool is_power = (power != 1.0f && is_decimal && has_min_max && (v_max - v_min < FLT_MAX)); if (is_power) { // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range From 7a5058e3bfea4149acef2ad98d8fdd62605a0f4c Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 14 Jan 2019 17:41:44 +0100 Subject: [PATCH 120/195] Version 1.67 --- docs/CHANGELOG.txt | 8 ++++---- imgui.cpp | 3 ++- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f97de110..b9a5fc55 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,10 +35,10 @@ HOW TO UPDATE? Breaking Changes: +- Made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable + side-effect because the window would have ID zero. In particular it is causing problems in viewport/docking branches. - Renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges and removed its [Beta] mark. The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. -- Made it illegal to call Begin("") with an empty string. This somehow accidentally worked before but had various - undesirable side-effect as the window would have ID zero. In particular it is causing problems in viewport/docking branches. - Renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). Other Changes: @@ -51,8 +51,8 @@ Other Changes: - Demo: Added "Documents" example app showcasing possible use for tabs. This feature was merged from the Docking branch in order to allow the use of regular tabs in your code. (It does not provide the docking/splitting/merging of windows available in the Docking branch) -- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, - as a convenience to avoid using the ### operator. In the Docking branch this also has an effect on tab closing behavior. +- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience + to avoid using the ### operator. In the Docking branch this also has an effect on tab closing behavior. - Window, Focus, Popup: Fixed an issue where closing a popup by clicking another window with the _NoMove flag would refocus the parent window of the popup instead of the newly clicked window. - Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. diff --git a/imgui.cpp b/imgui.cpp index 5a13076a..ac3580e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 WIP +// dear imgui, v1.67 // (main code and documentation) // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. @@ -366,6 +366,7 @@ CODE - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete). + - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects. - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). diff --git a/imgui.h b/imgui.h index d1be69d0..26d642b7 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.67 WIP +// dear imgui, v1.67 // (headers) // See imgui.cpp file for documentation. @@ -45,8 +45,8 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens) -#define IMGUI_VERSION "1.67 WIP" -#define IMGUI_VERSION_NUM 16602 +#define IMGUI_VERSION "1.67" +#define IMGUI_VERSION_NUM 16603 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 20a1434d..d5806401 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 WIP +// dear imgui, v1.67 // (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 4b9639c7..12686849 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 WIP +// dear imgui, v1.67 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index fad2c1bb..174d1af3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.67 WIP +// dear imgui, v1.67 // (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 b14db7e3..058d6a4c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 WIP +// dear imgui, v1.67 // (widgets code) /* From b8c6e31c2de36d80ed16af54b80ae8e489964f84 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 15:05:56 +0100 Subject: [PATCH 121/195] Fixed cursor issue caused by 6890e08b when calling BeginChild/EndChild multiple times to reappend into a same child window. (#2282) --- imgui.cpp | 3 ++- imgui_demo.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ac3580e3..9bdd8eed 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4276,7 +4276,8 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. // While this is not really documented/defined, it seems that the expected thing to do. - parent_window->DC.CursorPos = child_window->Pos; + if (child_window->BeginCount == 1) + parent_window->DC.CursorPos = child_window->Pos; // Process navigation-in immediately so NavInit can run on first frame if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d5806401..c5cd34aa 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1983,7 +1983,7 @@ static void ShowDemoWindowLayout() { ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); - ImGui::End(); + ImGui::EndChild(); } ImGui::TreePop(); } From d38d7c6628bebd02692cfdd6fa76b4d992a35b75 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 15:06:24 +0100 Subject: [PATCH 122/195] TODO update + internals: changed order or ImGuiLayoutType enums to allow using them for indexing. --- docs/TODO.txt | 29 +++++++++++++++-------------- imgui_internal.h | 6 ++++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 00eeead9..13c8dbe9 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -8,16 +8,12 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - doc/test: add a proper documentation+regression testing system (#435) - doc/test: checklist app to verify binding/integration of imgui (test inputs, rendering, callback, etc.). - doc/tips: tips of the day: website? applet in imgui_club? - - project: folder or separate repository with maintained helpers (e.g. imgui_memory_editor.h, imgui_stl.h, maybe imgui_dock would be there?) - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690) - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. - window: auto-fit feedback loop when user relies on any dynamic layout (window width multiplier, column) appears weird to end-user. clarify. - window: allow resizing of child windows (possibly given min/max for each axis?.) - window: background options for child windows, border option (disable rounding). - - window: resizing from any sides? done. > need backends to honor mouse cursors properly. (#822) - - window: resize from borders: support some form of outer padding to make it easier to grab borders. (#822) - - window: fix resize glitch when collapsing an AlwaysAutoResize window. - window: begin with *p_open == false could return false. - window: get size/pos helpers given names (see discussion in #249) - window: a collapsed window can be stuck behind the main menu bar? @@ -28,9 +24,10 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: expose contents size. (#1045) - window: using SetWindowPos() inside Begin() and moving the window with the mouse reacts a very ugly glitch. We should just defer the SetWindowPos() call. - window: GetWindowSize() returns (0,0) when not calculated? (#1045) - - window: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. - 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. - 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/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero. - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse) - scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet. - scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y). (2017-08-20: can't repro) @@ -99,7 +96,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - columns: sizing policy (e.g. for each column: fixed size, %, fill, distribute default size among fills) (#513, #125) - columns: add a conditional parameter to SetColumnOffset() (#513, #125) - - columns: headers. reorderable. (#513, #125) + - columns: headers. re-orderable. (#513, #125) - columns: optional sorting modifiers (up/down), sort list so sorting can be done multi-criteria. notify user when sort order changed. - columns: option to alternate background colors on odd/even scanlines. - columns: allow columns to recurse. @@ -126,7 +123,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - splitter/separator: formalize the splitter idiom into an official api (we want to handle n-way split) (#319) - - dock: docking extension + - dock: merge docking branch (#2109) - dock: dock out from a collapsing header? would work nicely but need emitting window to keep submitting the code. - tabs: make EndTabBar fail if users doesn't respect BeginTabBar return value, for consistency/future-proofing. @@ -134,7 +131,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - ext: stl-ish friendly extension (imgui_stl.h) that has wrapper for std::string, std::vector etc. - - button: provide a button that looks framed. + - button: provide a button that looks framed. (?) - image/image button: misalignment on padded/bordered button? - image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that? - image button: not taking an explicit id is odd. @@ -146,7 +143,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - slider: step option (#1183) - slider style: fill % of the bar instead of positioning a drag. - knob: rotating knob widget (#942) + - drag float: power/logarithmic slider and drags are weird. (#1316) - drag float: up/down axis + - drag float: power != 0.0f with current value being outside the the range keeps the value stuck. - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) - combo: use clipper: make it easier to disable clipper with a single flag. @@ -202,7 +201,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437) - stb: add defines to disable stb implementations -!- style: better default styles. (#707) + - style: better default styles. (#707) - style: add a highlighted text color (for headers, etc.) - style: border types: out-screen, in-screen, etc. (#447) - style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier) @@ -223,6 +222,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - filters: handle wild-cards (with implicit leading/trailing *), reg-exprs - filters: fuzzy matches (may use code at blog.forrestthewoods.com/4cffeed33fdb) + - drag and drop: releasing a drop shows the "..." tooltip for one frame - since e13e598 (#1725) - 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) @@ -243,6 +243,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data - font: PushFontSize API (#1018) - font: MemoryTTF taking ownership confusing/not obvious, maybe default should be opposite? + - font/demo: add tools to show glyphs used by a text blob, display U16 value, list missing glyphs. + - font/demo: demonstrate use of ImFontGlyphRangesBuilder. - font/atlas: add a missing Glyphs.reserve() - font/atlas: incremental updates - font/atlas: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier. @@ -250,7 +252,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: 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). + - 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) - font: fix AddRemapChar() to work before font has been built. @@ -292,13 +294,12 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - 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) - - misc: idle refresh: expose cursor blink animation timer for backend to be able to lower framerate. + - 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. - misc: make the ImGuiCond values linear (non-power-of-two). internal storage for ImGuiWindow can use integers to combine into flags (Why?) - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - misc: PushItemFlag(): add a flag to disable keyboard capture when used with mouse? (#1682) - misc: use more size_t in public api? - - misc: ImVector: erase_unsorted() helper - - misc: imgui_cpp: perhaps a misc/ header file with more friendly helper (e.g. type-infer versions of DragScalar, vector<> variants if appropriate for some functions). - backend: bgfx? https://gist.github.com/RichardGale/6e2b74bc42b3005e08397236e4be0fd0 - web/emscriptem: refactor some examples to facilitate integration with emscripten main loop system. (#1713, #336) @@ -309,7 +310,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - demo: find a way to demonstrate textures in the examples application, as it such a a common issue for new users. - demo: add vertical separator demo - demo: add virtual scrolling example? - - demo: demonstration Plot offset + - demo: demonstrate Plot offset - examples: window minimize, maximize (#583) - examples: provide a zero frame-rate/idle example. - examples: apple: example_apple should be using modern GL3. diff --git a/imgui_internal.h b/imgui_internal.h index 174d1af3..f7137c93 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -364,12 +364,14 @@ enum ImGuiItemStatusFlags_ }; // FIXME: this is in development, not exposed/functional as a generic feature yet. +// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 enum ImGuiLayoutType_ { - ImGuiLayoutType_Vertical = 0, - ImGuiLayoutType_Horizontal = 1 + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 }; +// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 enum ImGuiAxis { ImGuiAxis_None = -1, From 95ee99e6aa3127e2507d347d08b05cdda309bfaf Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 20:19:05 +0100 Subject: [PATCH 123/195] Version 1.68 WIP --- docs/CHANGELOG.txt | 7 ++++++- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 7 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b9a5fc55..840e8aa9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -30,7 +30,12 @@ HOW TO UPDATE? ----------------------------------------------------------------------- - VERSION 1.67 (In Progress) + VERSION 1.68 +----------------------------------------------------------------------- + + +----------------------------------------------------------------------- + VERSION 1.67 (Released 2019-01-14) ----------------------------------------------------------------------- Breaking Changes: diff --git a/imgui.cpp b/imgui.cpp index 9bdd8eed..8a59705e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 +// dear imgui, v1.68 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 26d642b7..dba7d908 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.67 +// dear imgui, v1.68 WIP // (headers) // See imgui.cpp file for documentation. @@ -45,8 +45,8 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens) -#define IMGUI_VERSION "1.67" -#define IMGUI_VERSION_NUM 16603 +#define IMGUI_VERSION "1.68 WIP" +#define IMGUI_VERSION_NUM 16800 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c5cd34aa..30303285 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 +// dear imgui, v1.68 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 12686849..21f52bfe 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 +// dear imgui, v1.68 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index f7137c93..14296b51 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.67 +// dear imgui, v1.68 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 058d6a4c..8ccf8bdf 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.67 +// dear imgui, v1.68 WIP // (widgets code) /* From 133f112af0e26746303556ef37059f6485e092b3 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 20:26:33 +0100 Subject: [PATCH 124/195] Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. (#1951, #2087, #2156, #2232) [many people] --- docs/CHANGELOG.txt | 4 ++++ examples/imgui_impl_win32.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 840e8aa9..79a9a644 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -33,6 +33,10 @@ HOW TO UPDATE? VERSION 1.68 ----------------------------------------------------------------------- +Other Changes: +- Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created + in a different thread. (#1951, #2087, #2156, #2232) [many people] + ----------------------------------------------------------------------- VERSION 1.67 (Released 2019-01-14) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 402025b3..be983fd5 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -18,6 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-01-15: Inputs: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. // 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads). @@ -134,7 +135,7 @@ static void ImGui_ImplWin32_UpdateMousePos() // Set mouse position io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); POINT pos; - if (::GetActiveWindow() == g_hWnd && ::GetCursorPos(&pos)) + if (::GetForegroundWindow() == g_hWnd && ::GetCursorPos(&pos)) if (::ScreenToClient(g_hWnd, &pos)) io.MousePos = ImVec2((float)pos.x, (float)pos.y); } From f435aa193b3a9956cc6ab6f774c7d491c5188051 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 21:17:48 +0100 Subject: [PATCH 125/195] Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). --- docs/CHANGELOG.txt | 1 + examples/imgui_impl_glfw.cpp | 2 +- examples/imgui_impl_win32.cpp | 68 +++++++++++++++++++++++++++++++++-- examples/imgui_impl_win32.h | 3 +- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 79a9a644..543ded7a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,6 +36,7 @@ HOW TO UPDATE? Other Changes: - Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. (#1951, #2087, #2156, #2232) [many people] +- Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). ----------------------------------------------------------------------- diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 0ff27446..4f107115 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -286,7 +286,7 @@ void ImGui_ImplGlfw_NewFrame() ImGui_ImplGlfw_UpdateMousePosAndButtons(); ImGui_ImplGlfw_UpdateMouseCursor(); - // Gamepad navigation mapping [BETA] + // Gamepad navigation mapping memset(io.NavInputs, 0, sizeof(io.NavInputs)); if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) { diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index be983fd5..d9927a78 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -5,8 +5,7 @@ // [X] Platform: Clipboard support (for Win32 this is actually part of core imgui) // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). -// Missing features: -// [ ] Platform: Gamepad support (best leaving it to user application to fill io.NavInputs[] with gamepad inputs from their source of choice). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. #include "imgui.h" #include "imgui_impl_win32.h" @@ -14,11 +13,13 @@ #define WIN32_LEAN_AND_MEAN #endif #include +#include #include // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2019-01-15: Inputs: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. +// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. // 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads). @@ -40,6 +41,8 @@ static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; +static bool g_HasGamepad = false; +static bool g_WantUpdateHasGamepad = true; // Functions bool ImGui_ImplWin32_Init(void* hwnd) @@ -140,6 +143,57 @@ static void ImGui_ImplWin32_UpdateMousePos() io.MousePos = ImVec2((float)pos.x, (float)pos.y); } +#ifdef _MSC_VER +#pragma comment(lib, "xinput") +#endif + +// Gamepad navigation mapping +void ImGui_ImplWin32_UpdateGameControllers() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. + // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. + if (g_WantUpdateHasGamepad) + { + XINPUT_CAPABILITIES caps; + g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); + g_WantUpdateHasGamepad = false; + } + + XINPUT_STATE xinput_state; + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) + { + const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + + #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } + #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); + #undef MAP_BUTTON + #undef MAP_ANALOG + } +} + void ImGui_ImplWin32_NewFrame() { ImGuiIO& io = ImGui::GetIO(); @@ -173,12 +227,18 @@ void ImGui_ImplWin32_NewFrame() g_LastMouseCursor = mouse_cursor; ImGui_ImplWin32_UpdateMouseCursor(); } + + // Update game controllers (if available) + ImGui_ImplWin32_UpdateGameControllers(); } // Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. #ifndef WM_MOUSEHWHEEL #define WM_MOUSEHWHEEL 0x020E #endif +#ifndef DBT_DEVNODES_CHANGED +#define DBT_DEVNODES_CHANGED 0x0007 +#endif // Process Win32 mouse/keyboard inputs. // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. @@ -246,6 +306,10 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) return 1; return 0; + case WM_DEVICECHANGE: + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + g_WantUpdateHasGamepad = true; + return 0; } return 0; } diff --git a/examples/imgui_impl_win32.h b/examples/imgui_impl_win32.h index 3d07bdea..76161860 100644 --- a/examples/imgui_impl_win32.h +++ b/examples/imgui_impl_win32.h @@ -5,8 +5,7 @@ // [X] Platform: Clipboard support (for Win32 this is actually part of core imgui) // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). -// Missing features: -// [ ] Platform: Gamepad support (best leaving it to user application to fill io.NavInputs[] with gamepad inputs from their source of choice). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. #pragma once From 79d497edae41c127b3220e64896c650cddde175b Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 21:20:00 +0100 Subject: [PATCH 126/195] Viewport: Made platform_io.Monitors mandatory for proper multi-viewport use. --- imgui.cpp | 3 ++- imgui.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 79090f7b..5eb583b8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3427,6 +3427,7 @@ void ImGui::NewFrame() IM_ASSERT(g.PlatformIO.Platform_SetWindowPos != NULL && "Platform init didn't install handlers?"); IM_ASSERT(g.PlatformIO.Platform_GetWindowSize != NULL && "Platform init didn't install handlers?"); IM_ASSERT(g.PlatformIO.Platform_SetWindowSize != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Monitors.Size > 0 && "Platform init didn't setup Monitors list?"); IM_ASSERT((g.Viewports[0]->PlatformUserData != NULL || g.Viewports[0]->PlatformHandle != NULL) && "Platform init didn't setup main viewport."); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IM_ASSERT(g.IO.RenderDrawListsFn == NULL); // Call ImGui::Render() then pass ImGui::GetDrawData() yourself to your render function! @@ -10445,7 +10446,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); if (g.PlatformIO.Monitors.Size > 0 && ImGui::TreeNode("Monitors", "Monitors (%d)", g.PlatformIO.Monitors.Size)) { - ImGui::TextWrapped("(When viewports are enabled, imgui optionally uses monitor data to position popup/tooltips so they don't straddle monitors.)"); + ImGui::TextWrapped("(When viewports are enabled, imgui needs uses monitor data to position popup/tooltips so they don't straddle monitors.)"); for (int i = 0; i < g.PlatformIO.Monitors.Size; i++) { const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i]; diff --git a/imgui.h b/imgui.h index f22fd40d..03f5bbc5 100644 --- a/imgui.h +++ b/imgui.h @@ -2174,8 +2174,8 @@ struct ImFont // - if you are new to dear imgui and trying to integrate it into your engine, you should probably ignore this for now. //----------------------------------------------------------------------------- -// (Optional) Represent the bounds of each connected monitor/display and their DPI -// This is used for: multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors. +// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI. +// We use this information for multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors. struct ImGuiPlatformMonitor { ImVec2 MainPos, MainSize; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) From daac9c755978ce1912d4882e2971c51bbec2e936 Mon Sep 17 00:00:00 2001 From: alexey_skryabin Date: Tue, 15 Jan 2019 18:25:30 +0500 Subject: [PATCH 127/195] By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree(). ImGuiFreeType::SetAllocatorFunctions() can be used to specify custom allocator. --- misc/freetype/README.md | 1 - misc/freetype/imgui_freetype.cpp | 69 ++++++++++++++++++++++++++++++-- misc/freetype/imgui_freetype.h | 4 ++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 885451a4..156e6511 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -121,6 +121,5 @@ struct FreeTypeTest ``` ### Known issues -- FreeType's memory allocator is not overridden. - `cfg.OversampleH`, `OversampleV` are ignored (but perhaps not so necessary with this rasterizer). diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 7c5403b6..814f506a 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -18,7 +18,6 @@ // For correct results you need to be using sRGB and convert to linear space in the pixel shader output. // The default imgui styles will be impacted by this change (alpha values will need tweaking). -// FIXME: FreeType's memory allocator is not overridden. // FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). #include "imgui_freetype.h" @@ -26,6 +25,7 @@ #include #include #include FT_FREETYPE_H // +#include FT_MODULE_H // #include FT_GLYPH_H // #include FT_SYNTHESIS_H // @@ -115,7 +115,6 @@ namespace bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags) { - // FIXME: substitute allocator FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); if (error != 0) return false; @@ -566,15 +565,77 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns return true; } +static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { (void)user_data; return ImGui::MemAlloc(size); } +static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { (void)user_data; ImGui::MemFree(ptr); } + +static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc; +static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc; +static void* GImFreeTypeAllocatorUserData = NULL; + +static void* FreeType_Alloc(FT_Memory memory, long size) +{ + (void)memory; + return GImFreeTypeAllocFunc(size, GImFreeTypeAllocatorUserData); +} + +static void FreeType_Free(FT_Memory memory, void* block) +{ + (void)memory; + GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); +} + +static void* FreeType_Realloc(FT_Memory memory, long cur_size, long new_size, void* block) +{ + // Implement realloc() as we don't ask user to provide it. + + (void)memory; + + if (!block) + return GImFreeTypeAllocFunc(new_size, GImFreeTypeAllocatorUserData); + + if (new_size == 0) + { + GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); + return nullptr; + } + + if (new_size > cur_size) + { + void* new_block = GImFreeTypeAllocFunc(new_size, GImFreeTypeAllocatorUserData); + memcpy(new_block, block, cur_size); + GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); + block = new_block; + } + + return block; +} + bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) { + // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html + FT_MemoryRec_ memoryRec = {0}; + memoryRec.alloc = &FreeType_Alloc; + memoryRec.free = &FreeType_Free; + memoryRec.realloc = &FreeType_Realloc; + + // https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library FT_Library ft_library; - FT_Error error = FT_Init_FreeType(&ft_library); + FT_Error error = FT_New_Library(&memoryRec, &ft_library); if (error != 0) return false; + // NB: If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. + FT_Add_Default_Modules(ft_library); + bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags); - FT_Done_FreeType(ft_library); + FT_Done_Library(ft_library); return ret; } + +void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data) +{ + GImFreeTypeAllocFunc = alloc_func; + GImFreeTypeFreeFunc = free_func; + GImFreeTypeAllocatorUserData = user_data; +} \ No newline at end of file diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index aa0aba63..90f4b94c 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -28,4 +28,8 @@ namespace ImGuiFreeType }; IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); + + // FreeType does lots of allocations so user might want to provide separate memory heap. + // By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree(). + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); } From 09f1cb642bf58dc009629d83f0dea914987ce753 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 15 Jan 2019 21:50:43 +0100 Subject: [PATCH 128/195] FreeType: Minor tweaks previous commit (#2285) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 2 +- imgui.h | 2 +- misc/freetype/imgui_freetype.cpp | 57 ++++++++++++++++---------------- misc/freetype/imgui_freetype.h | 4 +-- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 543ded7a..110c6eea 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -34,6 +34,7 @@ HOW TO UPDATE? ----------------------------------------------------------------------- Other Changes: +- Fonts: imgui_freetype: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] - Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). diff --git a/imgui.cpp b/imgui.cpp index 8a59705e..7460b745 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2951,7 +2951,7 @@ bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si return !error; } -void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data) +void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) { GImAllocatorAllocFunc = alloc_func; GImAllocatorFreeFunc = free_func; diff --git a/imgui.h b/imgui.h index dba7d908..fbcf5f44 100644 --- a/imgui.h +++ b/imgui.h @@ -670,7 +670,7 @@ namespace ImGui // Memory Utilities // - All those functions are not reliant on the current context. // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again. - IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); IMGUI_API void* MemAlloc(size_t size); IMGUI_API void MemFree(void* ptr); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 814f506a..cef5a716 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -5,12 +5,13 @@ // Changelog: // - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks. // - v0.51: (2017/08/26) cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply. -// - v0.52: (2017/09/26) fixes for imgui internal changes -// - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement) -// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member +// - v0.52: (2017/09/26) fixes for imgui internal changes. +// - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement). +// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member. // - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club) -// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX +// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX. // - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding. +// - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions(). // Gamma Correct Blending: // FreeType assumes blending in linear space rather than gamma space. @@ -565,46 +566,44 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns return true; } +// Default memory allocators static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { (void)user_data; return ImGui::MemAlloc(size); } -static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { (void)user_data; ImGui::MemFree(ptr); } +static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { (void)user_data; ImGui::MemFree(ptr); } +// Current memory allocators static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc; -static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc; +static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc; static void* GImFreeTypeAllocatorUserData = NULL; -static void* FreeType_Alloc(FT_Memory memory, long size) +// FreeType memory allocation callbacks +static void* FreeType_Alloc(FT_Memory /*memory*/, long size) { - (void)memory; - return GImFreeTypeAllocFunc(size, GImFreeTypeAllocatorUserData); + return GImFreeTypeAllocFunc((size_t)size, GImFreeTypeAllocatorUserData); } -static void FreeType_Free(FT_Memory memory, void* block) +static void FreeType_Free(FT_Memory /*memory*/, void* block) { - (void)memory; GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); } -static void* FreeType_Realloc(FT_Memory memory, long cur_size, long new_size, void* block) +static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block) { // Implement realloc() as we don't ask user to provide it. - - (void)memory; - - if (!block) - return GImFreeTypeAllocFunc(new_size, GImFreeTypeAllocatorUserData); + if (block == NULL) + return GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData); if (new_size == 0) { GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); - return nullptr; + return NULL; } if (new_size > cur_size) { - void* new_block = GImFreeTypeAllocFunc(new_size, GImFreeTypeAllocatorUserData); - memcpy(new_block, block, cur_size); + void* new_block = GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData); + memcpy(new_block, block, (size_t)cur_size); GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData); - block = new_block; + return new_block; } return block; @@ -613,18 +612,18 @@ static void* FreeType_Realloc(FT_Memory memory, long cur_size, long new_size, vo bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) { // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html - FT_MemoryRec_ memoryRec = {0}; - memoryRec.alloc = &FreeType_Alloc; - memoryRec.free = &FreeType_Free; - memoryRec.realloc = &FreeType_Realloc; + FT_MemoryRec_ memory_rec = { 0 }; + memory_rec.alloc = &FreeType_Alloc; + memory_rec.free = &FreeType_Free; + memory_rec.realloc = &FreeType_Realloc; // https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library FT_Library ft_library; - FT_Error error = FT_New_Library(&memoryRec, &ft_library); + FT_Error error = FT_New_Library(&memory_rec, &ft_library); if (error != 0) return false; - // NB: If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. + // If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. FT_Add_Default_Modules(ft_library); bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags); @@ -633,9 +632,9 @@ bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) return ret; } -void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data) +void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) { GImFreeTypeAllocFunc = alloc_func; GImFreeTypeFreeFunc = free_func; GImFreeTypeAllocatorUserData = user_data; -} \ No newline at end of file +} diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 90f4b94c..a0503bff 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -29,7 +29,7 @@ namespace ImGuiFreeType IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); - // FreeType does lots of allocations so user might want to provide separate memory heap. // By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree(). - IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL); + // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired: + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); } From 2f9bae140b8b770804053668d1a0814ce5c4fb11 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 14:43:27 +0100 Subject: [PATCH 129/195] Docking: Demo: Fixed docking document window into parent window. (#2286) --- imgui_demo.cpp | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5f731361..66528bc6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4205,24 +4205,32 @@ void ShowExampleAppDocuments(bool* p_open) { static ExampleAppDocuments app; - if (!ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar)) - { - ImGui::End(); - return; - } - // Options enum Target { Target_None, - Target_Tab, // Create document as a local tab into a local tab bar - Target_Window // Create document as a regular window + Target_Tab, // Create documents as local tab into a local tab bar + Target_DockspaceAndWindow // Create documents as regular windows, and create an embedded dockspace }; static Target opt_target = Target_Tab; static bool opt_reorderable = true; static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; - // Menu + // When (opt_target == Target_DockspaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant") + // that we emit gets docked into the same spot as the parent window ("Example: Documents"). + // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab + // not visible, which in turn would stop submitting the "Eggplant" window. + // We avoid this problem by submitting our documents window even if our parent window is not currently visible. + // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking. + + bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); + if (!window_contents_visible && opt_target != Target_DockspaceAndWindow) + { + ImGui::End(); + return; + } + + // Menu Bar if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("File")) @@ -4267,8 +4275,8 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0"); ImGui::PopItemWidth(); bool redock_all = false; - if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); } - if (opt_target == Target_Window) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); } + if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); } + if (opt_target == Target_DockspaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); } ImGui::Separator(); @@ -4313,7 +4321,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::EndTabBar(); } } - else if (opt_target == Target_Window) + else if (opt_target == Target_DockspaceAndWindow) { if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) { @@ -4357,6 +4365,13 @@ void ShowExampleAppDocuments(bool* p_open) } } + // Early out other contents + if (!window_contents_visible) + { + ImGui::End(); + return; + } + // Update closing queue static ImVector close_queue; if (close_queue.empty()) From 882f1bc1352dd55e98c1b6d04522096b686c90ed Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 15:10:31 +0100 Subject: [PATCH 130/195] Examples: DirectX12: Targeting 10.0.14393.0 instead of 10.0.16299.0 (available on AppVeyor, and higher version doesn't seem necessary). --- .../example_win32_directx12/example_win32_directx12.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj b/examples/example_win32_directx12/example_win32_directx12.vcxproj index 38c83351..dabd6d84 100644 --- a/examples/example_win32_directx12/example_win32_directx12.vcxproj +++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj @@ -21,7 +21,7 @@ {b4cf9797-519d-4afe-a8f4-5141a6b521d3} example_win32_directx12 - 10.0.16299.0 + 10.0.14393.0 From 06aaf238770767bb6e9734ce1efef34a18f278f8 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 16:10:51 +0100 Subject: [PATCH 131/195] Various tweaks and fixes as suggested by PVS Studio (thanks PVS Studio!) --- imgui.cpp | 7 ++++--- imgui_demo.cpp | 36 +++++++++++++++++++----------------- imgui_draw.cpp | 7 ++++--- imgui_widgets.cpp | 20 +++++++++++++------- 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7460b745..ca4db658 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5115,7 +5115,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) { - ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + 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); } @@ -7514,6 +7514,7 @@ static void ImGui::NavUpdate() NavUpdateWindowing(); // Set output flags for user application + // FIXME: g.NavInitRequest is always false at this point, investigate the intent of operation done here. g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest; @@ -7749,7 +7750,7 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags) ImGuiWindow* window = g.NavWindow; bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up)); bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down)); - if ((page_up_held && !page_down_held) || (page_down_held && !page_up_held)) + if (page_up_held != page_down_held) // If either (not both) are pressed { if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) { @@ -8418,7 +8419,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. BeginTooltip(); - if (g.DragDropActive && g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) { ImGuiWindow* tooltip_window = g.CurrentWindow; tooltip_window->SkipItems = true; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 30303285..e4832c12 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -871,17 +871,18 @@ static void ShowDemoWindowWidgets() } if (ImGui::TreeNode("Grid")) { - static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; - for (int i = 0; i < 16; i++) + static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; + for (int i = 0; i < 4*4; i++) { ImGui::PushID(i); if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) { - int x = i % 4, y = i / 4; - if (x > 0) selected[i - 1] ^= 1; - if (x < 3) selected[i + 1] ^= 1; - if (y > 0) selected[i - 4] ^= 1; - if (y < 3) selected[i + 4] ^= 1; + int x = i % 4; + int y = i / 4; + if (x > 0) { selected[i - 1] ^= 1; } + if (x < 3) { selected[i + 1] ^= 1; } + if (y > 0) { selected[i - 4] ^= 1; } + if (y < 3) { selected[i + 4] ^= 1; } } if ((i % 4) < 3) ImGui::SameLine(); ImGui::PopID(); @@ -947,7 +948,7 @@ static void ShowDemoWindowWidgets() static float values[90] = { 0 }; static int values_offset = 0; static double refresh_time = 0.0; - if (!animate || refresh_time == 0.0f) + if (!animate || refresh_time == 0.0) refresh_time = ImGui::GetTime(); while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo { @@ -1975,9 +1976,9 @@ static void ShowDemoWindowLayout() ImGui::EndChild(); ImGui::PopStyleVar(2); float scroll_x_delta = 0.0f; - ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); + ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine(); - ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); + ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); if (scroll_x_delta != 0.0f) { @@ -2505,9 +2506,9 @@ static void ShowDemoWindowMisc() // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item static float f3[3] = { 0.0f, 0.0f, 0.0f }; int focus_ahead = -1; - if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine(); - if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine(); - if (ImGui::Button("Focus on Z")) focus_ahead = 2; + if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); + if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); + if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); @@ -3726,8 +3727,8 @@ static void ShowExampleAppConstrainedResize(bool* p_open) if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 - if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square - if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) @@ -3765,7 +3766,8 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) { const float DISTANCE = 10.0f; static int corner = 0; - ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE); + ImGuiIO& io = ImGui::GetIO(); + 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); if (corner != -1) ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); @@ -3775,7 +3777,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); ImGui::Separator(); if (ImGui::IsMousePosValid()) - ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); else ImGui::Text("Mouse Position: "); if (ImGui::BeginPopupContextWindow()) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 21f52bfe..103766da 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1518,7 +1518,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid GetTexDataAsAlpha8(&pixels, NULL, NULL); if (pixels) { - TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4)); + TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4); const unsigned char* src = pixels; unsigned int* dst = TexPixelsRGBA32; for (int n = TexWidth * TexHeight; n > 0; n--) @@ -2999,13 +2999,14 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im const float inv_rounding = 1.0f / rounding; const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); + const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. const float x0 = ImMax(p0.x, rect.Min.x + rounding); if (arc0_b == arc0_e) { draw_list->PathLineTo(ImVec2(x0, p1.y)); draw_list->PathLineTo(ImVec2(x0, p0.y)); } - else if (arc0_b == 0.0f && arc0_e == IM_PI*0.5f) + else if (arc0_b == 0.0f && arc0_e == half_pi) { draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR @@ -3025,7 +3026,7 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im draw_list->PathLineTo(ImVec2(x1, p0.y)); draw_list->PathLineTo(ImVec2(x1, p1.y)); } - else if (arc1_b == 0.0f && arc1_e == IM_PI*0.5f) + else if (arc1_b == 0.0f && arc1_e == half_pi) { draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8ccf8bdf..ade99fb0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -672,7 +672,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) // Render ImVec2 center = bb.GetCenter(); if (hovered) - window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); + window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); float cross_extent = (radius * 0.7071f) - 1.0f; ImU32 cross_col = GetColorU32(ImGuiCol_Text); @@ -1666,7 +1666,7 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; if (decimal_precision < 0) return FLT_MIN; - return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); } template @@ -3895,9 +3895,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (n + 1 == components) PushItemWidth(w_item_last); if (flags & ImGuiColorEditFlags_Float) - value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + { + value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed_as_float |= value_changed; + } else + { value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + } if (!(flags & ImGuiColorEditFlags_NoOptions)) OpenPopupOnItemClick("context"); } @@ -4000,7 +4005,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag { if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) { - memcpy((float*)col, payload->Data, sizeof(float) * 3); + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any value_changed = true; } if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) @@ -4582,7 +4587,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); SetCursorScreenPos(backup_pos); ImVec4 dummy_ref_col; - memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4)); + memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); PopID(); } @@ -4985,7 +4990,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags ImGuiItemHoveredDataBackup last_item_backup; float button_radius = g.FontSize * 0.5f; ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y); - if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), button_center, button_radius)) + if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius)) *p_open = false; last_item_backup.Restore(); } @@ -5804,6 +5809,7 @@ ImGuiTabBar::ImGuiTabBar() ID = 0; SelectedTabId = NextSelectedTabId = VisibleTabId = 0; CurrFrameVisible = PrevFrameVisible = -1; + ContentsHeight = 0.0f; OffsetMax = OffsetNextTab = 0.0f; ScrollingAnim = ScrollingTarget = 0.0f; Flags = ImGuiTabBarFlags_None; @@ -6417,7 +6423,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; // Render tab label, process close button - const ImGuiID close_button_id = p_open ? window->GetID((void*)(intptr_t)(id + 1)) : 0; + const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id); if (just_closed) { From 32c4e01267efca5bc97566a6df1ef5bb83cc29f7 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 16:10:51 +0100 Subject: [PATCH 132/195] Various tweaks and fixes as suggested by PVS Studio (thanks PVS Studio!) --- imgui.cpp | 7 ++++--- imgui_demo.cpp | 34 ++++++++++++++++++---------------- imgui_draw.cpp | 7 ++++--- imgui_widgets.cpp | 20 +++++++++++++------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 999a45db..d49d6584 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5595,7 +5595,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // in order for their pos/size to be matching their undocking state.) if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) { - ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + 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); } @@ -8840,6 +8840,7 @@ static void ImGui::NavUpdate() NavUpdateWindowing(); // Set output flags for user application + // FIXME: g.NavInitRequest is always false at this point, investigate the intent of operation done here. g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest; @@ -9075,7 +9076,7 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags) ImGuiWindow* window = g.NavWindow; bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up)); bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down)); - if ((page_up_held && !page_down_held) || (page_down_held && !page_up_held)) + if (page_up_held != page_down_held) // If either (not both) are pressed { if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) { @@ -9761,7 +9762,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. BeginTooltip(); - if (g.DragDropActive && g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) { ImGuiWindow* tooltip_window = g.CurrentWindow; tooltip_window->SkipItems = true; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 66528bc6..fb3f22cb 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -924,17 +924,18 @@ static void ShowDemoWindowWidgets() } if (ImGui::TreeNode("Grid")) { - static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; - for (int i = 0; i < 16; i++) + static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; + for (int i = 0; i < 4*4; i++) { ImGui::PushID(i); if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) { - int x = i % 4, y = i / 4; - if (x > 0) selected[i - 1] ^= 1; - if (x < 3) selected[i + 1] ^= 1; - if (y > 0) selected[i - 4] ^= 1; - if (y < 3) selected[i + 4] ^= 1; + int x = i % 4; + int y = i / 4; + if (x > 0) { selected[i - 1] ^= 1; } + if (x < 3) { selected[i + 1] ^= 1; } + if (y > 0) { selected[i - 4] ^= 1; } + if (y < 3) { selected[i + 4] ^= 1; } } if ((i % 4) < 3) ImGui::SameLine(); ImGui::PopID(); @@ -1000,7 +1001,7 @@ static void ShowDemoWindowWidgets() static float values[90] = { 0 }; static int values_offset = 0; static double refresh_time = 0.0; - if (!animate || refresh_time == 0.0f) + if (!animate || refresh_time == 0.0) refresh_time = ImGui::GetTime(); while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo { @@ -2032,9 +2033,9 @@ static void ShowDemoWindowLayout() ImGui::EndChild(); ImGui::PopStyleVar(2); float scroll_x_delta = 0.0f; - ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); + ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine(); - ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); + ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine(); ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); if (scroll_x_delta != 0.0f) { @@ -2562,9 +2563,9 @@ static void ShowDemoWindowMisc() // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item static float f3[3] = { 0.0f, 0.0f, 0.0f }; int focus_ahead = -1; - if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine(); - if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine(); - if (ImGui::Button("Focus on Z")) focus_ahead = 2; + if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); + if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); + if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); @@ -3811,8 +3812,8 @@ static void ShowExampleAppConstrainedResize(bool* p_open) if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 - if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square - if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) @@ -3853,6 +3854,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) // FIXME-VIEWPORT-ABS: Select a default viewport const float DISTANCE = 10.0f; static int corner = 0; + ImGuiIO& io = ImGui::GetIO(); if (corner != -1) { ImGuiViewport* viewport = ImGui::GetMainViewport(); @@ -3867,7 +3869,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); ImGui::Separator(); if (ImGui::IsMousePosValid()) - ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); else ImGui::Text("Mouse Position: "); if (ImGui::BeginPopupContextWindow()) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5d758239..4c30ccb5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1524,7 +1524,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid GetTexDataAsAlpha8(&pixels, NULL, NULL); if (pixels) { - TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4)); + TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4); const unsigned char* src = pixels; unsigned int* dst = TexPixelsRGBA32; for (int n = TexWidth * TexHeight; n > 0; n--) @@ -3026,13 +3026,14 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im const float inv_rounding = 1.0f / rounding; const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); + const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. const float x0 = ImMax(p0.x, rect.Min.x + rounding); if (arc0_b == arc0_e) { draw_list->PathLineTo(ImVec2(x0, p1.y)); draw_list->PathLineTo(ImVec2(x0, p0.y)); } - else if (arc0_b == 0.0f && arc0_e == IM_PI*0.5f) + else if (arc0_b == 0.0f && arc0_e == half_pi) { draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR @@ -3052,7 +3053,7 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im draw_list->PathLineTo(ImVec2(x1, p0.y)); draw_list->PathLineTo(ImVec2(x1, p1.y)); } - else if (arc1_b == 0.0f && arc1_e == IM_PI*0.5f) + else if (arc1_b == 0.0f && arc1_e == half_pi) { draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 60004526..22278109 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -673,7 +673,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) // Render ImVec2 center = bb.GetCenter(); if (hovered) - window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); + window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); float cross_extent = (radius * 0.7071f) - 1.0f; ImU32 cross_col = GetColorU32(ImGuiCol_Text); @@ -1697,7 +1697,7 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; if (decimal_precision < 0) return FLT_MIN; - return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); } template @@ -3929,9 +3929,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (n + 1 == components) PushItemWidth(w_item_last); if (flags & ImGuiColorEditFlags_Float) - value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + { + value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed_as_float |= value_changed; + } else + { value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + } if (!(flags & ImGuiColorEditFlags_NoOptions)) OpenPopupOnItemClick("context"); } @@ -4034,7 +4039,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag { if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) { - memcpy((float*)col, payload->Data, sizeof(float) * 3); + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any value_changed = true; } if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) @@ -4616,7 +4621,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); SetCursorScreenPos(backup_pos); ImVec4 dummy_ref_col; - memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4)); + memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); PopID(); } @@ -5019,7 +5024,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags ImGuiItemHoveredDataBackup last_item_backup; float button_radius = g.FontSize * 0.5f; ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y); - if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), button_center, button_radius)) + if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius)) *p_open = false; last_item_backup.Restore(); } @@ -5842,6 +5847,7 @@ ImGuiTabBar::ImGuiTabBar() ID = 0; SelectedTabId = NextSelectedTabId = VisibleTabId = 0; CurrFrameVisible = PrevFrameVisible = -1; + ContentsHeight = 0.0f; OffsetMax = OffsetNextTab = 0.0f; ScrollingAnim = ScrollingTarget = 0.0f; Flags = ImGuiTabBarFlags_None; @@ -6576,7 +6582,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; // Render tab label, process close button - const ImGuiID close_button_id = p_open ? window->GetID((void*)(intptr_t)(id + 1)) : 0; + const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id); if (just_closed) { From d1851ed6b7f7a350f50a275bbbfd2b61d5553111 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 16:19:38 +0100 Subject: [PATCH 133/195] Various tweaks and fixes as suggested by PVS Studio (thanks PVS Studio!) [docking branch] --- imgui.cpp | 18 ++++++++---------- imgui_internal.h | 1 + imgui_widgets.cpp | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d49d6584..438f89fa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5064,10 +5064,11 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags window->ParentWindow = parent_window; window->RootWindow = window->RootWindowDockStop = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + { window->RootWindow = parent_window->RootWindow; - if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) if (!window->DockIsActive && !(parent_window->Flags & ImGuiWindowFlags_DockNodeHost)) window->RootWindowDockStop = parent_window->RootWindowDockStop; + } if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) @@ -10507,12 +10508,9 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) ImGuiDockNode* inheritor_node = target_node->ChildNodes[split_inheritor_child_idx]; ImGuiDockNode* new_node = target_node->ChildNodes[split_inheritor_child_idx ^ 1]; new_node->HostWindow = target_node->HostWindow; - if (target_node) - { - inheritor_node->IsCentralNode = target_node->IsCentralNode; - inheritor_node->IsHiddenTabBar = target_node->IsHiddenTabBar; - target_node->IsCentralNode = false; - } + inheritor_node->IsCentralNode = target_node->IsCentralNode; + inheritor_node->IsHiddenTabBar = target_node->IsHiddenTabBar; + target_node->IsCentralNode = false; target_node = new_node; } target_node->IsHiddenTabBar = false; @@ -11453,7 +11451,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass; @@ -12776,7 +12774,7 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window) DockNodePreviewDockRender(window, target_node, payload_window, &split_outer); // Queue docking request - if (split_data && split_data->IsDropAllowed && payload->IsDelivery()) + if (split_data->IsDropAllowed && payload->IsDelivery()) DockContextQueueDock(ctx, window, split_data->SplitNode, payload_window, split_data->SplitDir, split_data->SplitRatio, split_data == &split_outer); } } @@ -13057,7 +13055,7 @@ void ImGui::LogToFile(int max_depth, const char* filename) IM_ASSERT(g.LogFile == NULL); g.LogFile = ImFileOpen(filename, "ab"); - if (!g.LogFile) + if (g.LogFile == NULL) { IM_ASSERT(g.LogFile != NULL); // Consider this an error return; diff --git a/imgui_internal.h b/imgui_internal.h index d8655b1f..d62088ce 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1057,6 +1057,7 @@ struct ImGuiContext CurrentWindow = NULL; HoveredWindow = NULL; HoveredRootWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; HoveredId = 0; HoveredIdAllowOverlap = false; HoveredIdPreviousFrame = 0; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 22278109..3832ae13 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6527,7 +6527,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, { // We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id); - if (!undocking_tab && held) + if (!undocking_tab) { //if (!g.IO.ConfigDockingWithShift || g.IO.KeyShift) { From 8cbb91261ea419c272f3f2d68849ecce28e85728 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 17:47:49 +0100 Subject: [PATCH 134/195] ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] + Demo tweaks --- docs/CHANGELOG.txt | 2 ++ docs/TODO.txt | 2 +- imgui_demo.cpp | 27 +++++++++++++++------------ imgui_draw.cpp | 13 +++++++++---- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 110c6eea..85771c9e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -34,6 +34,8 @@ HOW TO UPDATE? ----------------------------------------------------------------------- Other Changes: +- ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" + with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - Fonts: imgui_freetype: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] - Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. (#1951, #2087, #2156, #2232) [many people] diff --git a/docs/TODO.txt b/docs/TODO.txt index 13c8dbe9..624e6309 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -38,7 +38,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). - drawlist: primitives/helpers to manipulate vertices post submission, so e.g. a quad/rect can be resized to fit later submitted content, _without_ using the ChannelSplit api - drawlist: make it easier to toggle AA per primitive, so we can use e.g. non-AA fill + AA borders more naturally - - drawlist: non-AA strokes have gaps between points (#593, #288), especially RenderCheckmark(). + - drawlist: non-AA strokes have gaps between points (#593, #288), glitch especially on RenderCheckmark() and ColorPicker4(). - drawlist: would be good to be able to deep copy of ImDrawData (we have a deep copy of ImDrawList now). - drawlist: rendering: provide a way for imgui to output to a single/global vertex buffer, re-order indices only at the end of the frame (ref: https://gist.github.com/floooh/10388a0afbe08fce9e617d8aefa7d302) - drawlist: callback: add an extra void* in ImDrawCallback to allow passing render-local data to the callback (would break API). diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e4832c12..e3b625ed 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3852,27 +3852,30 @@ static void ShowExampleAppCustomRendering(bool* p_open) static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); - ImGui::ColorEdit3("Color", &col.x); + ImGui::ColorEdit4("Color", &col.x); { const ImVec2 p = ImGui::GetCursorScreenPos(); const ImU32 col32 = ImColor(col); float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f; for (int n = 0; n < 2; n++) { - float curr_thickness = (n == 0) ? 1.0f : thickness; - draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, curr_thickness); x += sz+spacing; - draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, curr_thickness); x += sz+spacing; - draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, curr_thickness); x += sz+spacing; - draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, curr_thickness); x += sz+spacing; - draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, curr_thickness); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, curr_thickness); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, curr_thickness); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) - draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, curr_thickness); x += sz+spacing; // Diagonal line - draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, curr_thickness); + // First line uses a thickness of 1.0, second line uses the configurable thickness + float th = (n == 0) ? 1.0f : thickness; + draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6, th); x += sz+spacing; // Hexagon + draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, th); x += sz+spacing; // Circle + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, th); x += sz+spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, th); x += sz+spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, th); x += sz+spacing; + draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, th); x += sz+spacing; + draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, th); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, th); x += sz+spacing; // Diagonal line + draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, th); x = p.x + 4; y += sz+spacing; } - draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; + draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6); x += sz+spacing; // Hexagon + draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; // Circle draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight); x += sz+spacing; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 103766da..f20f15ab 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -955,6 +955,9 @@ void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, floa _Path.push_back(centre); return; } + + // 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! _Path.reserve(_Path.Size + (num_segments + 1)); for (int i = 0; i <= num_segments; i++) { @@ -1138,21 +1141,23 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness) { - if ((col & IM_COL32_A_MASK) == 0) + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; + // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; - PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments); + PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1); PathStroke(col, true, thickness); } void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments) { - if ((col & IM_COL32_A_MASK) == 0) + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) return; + // Because we are filling a closed shape we remove 1 from the count of segments/points const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; - PathArcTo(centre, radius, 0.0f, a_max, num_segments); + PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1); PathFillConvex(col); } From 83810039d1f2a69c61f715c44e8c01cce7fc0cdf Mon Sep 17 00:00:00 2001 From: Chris Savoie Date: Wed, 22 Aug 2018 22:19:55 -0700 Subject: [PATCH 135/195] Add editor config for 4 spaces instead of tab. --- .editorconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..e38e2195 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# editorconfig.org + +# top-most EditorConfig file +root = true + +# Default settings: +# Use 4 spaces as indentation +[*] +indent_style = space +indent_size = 4 From f2c92808f8fa014322f5bfc0950ac4d27d6dbf6d Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 16 Jan 2019 22:02:42 +0100 Subject: [PATCH 136/195] EditorConfig: Further tweaks (#2038) --- .editorconfig | 7 +++++++ docs/CHANGELOG.txt | 1 + 2 files changed, 8 insertions(+) diff --git a/.editorconfig b/.editorconfig index e38e2195..39320baa 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,10 @@ root = true [*] indent_style = space indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +# Makefile +[Makefile] +indent_style = tab +indent_size = 4 diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 85771c9e..83ccbcee 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -34,6 +34,7 @@ HOW TO UPDATE? ----------------------------------------------------------------------- Other Changes: +- Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - Fonts: imgui_freetype: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] From 14c40242dbf7f46ada9319f2f7bf565a77bdee40 Mon Sep 17 00:00:00 2001 From: Gilad Reich Date: Thu, 17 Jan 2019 06:07:15 +0100 Subject: [PATCH 137/195] Examples: DirectX9: Explicitly disable fog (D3DRS_FOGENABLE) before drawing in case user state has it set. (#2288, #2290) --- docs/CHANGELOG.txt | 3 ++- examples/imgui_impl_dx9.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 83ccbcee..b7c558ec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -30,7 +30,7 @@ HOW TO UPDATE? ----------------------------------------------------------------------- - VERSION 1.68 + VERSION 1.68 (In progress) ----------------------------------------------------------------------- Other Changes: @@ -41,6 +41,7 @@ Other Changes: - Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). +- Examples: DirectX9: Explicitly disable fog (D3DRS_FOGENABLE) before drawing in case user state has it set. (#2288, #2230) ----------------------------------------------------------------------- diff --git a/examples/imgui_impl_dx9.cpp b/examples/imgui_impl_dx9.cpp index 5d3287e8..e3e12071 100644 --- a/examples/imgui_impl_dx9.cpp +++ b/examples/imgui_impl_dx9.cpp @@ -10,6 +10,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example. // 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. @@ -131,6 +132,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true); g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); From 872477548b1b0a770d20241875a96b5f3723d6b0 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 17 Jan 2019 11:45:32 +0100 Subject: [PATCH 138/195] Examples: Win32: Using IsChild() to be compatible with windows created within a parent. (#1951, #2087, #2156, #2232) --- docs/CHANGELOG.txt | 4 ++-- examples/imgui_impl_win32.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b7c558ec..01380d36 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -38,8 +38,8 @@ Other Changes: - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - Fonts: imgui_freetype: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] -- Examples: Win32: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created - in a different thread. (#1951, #2087, #2156, #2232) [many people] +- Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created + in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). - Examples: DirectX9: Explicitly disable fog (D3DRS_FOGENABLE) before drawing in case user state has it set. (#2288, #2230) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index d9927a78..0e6c675e 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -18,7 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2019-01-15: Inputs: Using GetForegroundWindow() instead of GetActiveWindow() to be compatible with windows created in a different thread. +// 2019-01-17: Inputs: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. // 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. @@ -138,9 +138,10 @@ static void ImGui_ImplWin32_UpdateMousePos() // Set mouse position io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); POINT pos; - if (::GetForegroundWindow() == g_hWnd && ::GetCursorPos(&pos)) - if (::ScreenToClient(g_hWnd, &pos)) - io.MousePos = ImVec2((float)pos.x, (float)pos.y); + if (HWND active_window = ::GetForegroundWindow()) + if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd)) + if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos)) + io.MousePos = ImVec2((float)pos.x, (float)pos.y); } #ifdef _MSC_VER From acdb4823dd9a4c71ef621935c0310180ac29531a Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 17 Jan 2019 14:35:26 +0100 Subject: [PATCH 139/195] Examples: Win32: Fix for older Windows SDK. --- examples/imgui_impl_win32.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 230fc22b..882ef805 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -411,6 +411,8 @@ typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_ #ifndef _DPI_AWARENESS_CONTEXTS_ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3 +#endif +#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4 #endif typedef HRESULT(WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib+dll, Windows 8.1 From bebb07f12da512694a14f12195695357251bc568 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 17 Jan 2019 16:48:11 +0100 Subject: [PATCH 140/195] ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093) --- docs/CHANGELOG.txt | 3 ++- imgui_draw.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 01380d36..05d26622 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,7 +37,8 @@ Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] -- Fonts: imgui_freetype: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] +- ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093) +- ImFontAtlas: FreeType: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] - Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f20f15ab..a3c48fc8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2167,7 +2167,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() static const ImWchar ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters 0x4e00, 0x9FAF, // CJK Ideograms @@ -2243,9 +2244,10 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() static ImWchar base_ranges[] = // not zero-terminated { 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0xFF00, 0xFFEF, // Half-width characters + 0xFF00, 0xFFEF // Half-width characters }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; if (!full_ranges[0]) @@ -2301,9 +2303,9 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() static ImWchar base_ranges[] = // not zero-terminated { 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0xFF00, 0xFFEF, // Half-width characters + 0xFF00, 0xFFEF // Half-width characters }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; if (!full_ranges[0]) From b8020032f92d43a18b118b562a99e91edd15841d Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 17 Jan 2019 16:55:23 +0100 Subject: [PATCH 141/195] Examples: Win32: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. (#2264) --- docs/CHANGELOG.txt | 1 + examples/imgui_impl_win32.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 05d26622..6b3f8775 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,6 +42,7 @@ Other Changes: - Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). +- Examples: Win32: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. (#2264) - Examples: DirectX9: Explicitly disable fog (D3DRS_FOGENABLE) before drawing in case user state has it set. (#2288, #2230) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 0e6c675e..616ee06a 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -18,7 +18,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2019-01-17: Inputs: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. +// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. +// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. // 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. @@ -259,11 +260,13 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: { int button = 0; - if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) button = 0; - if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) button = 1; - if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) button = 2; + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } + if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } + if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } + if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) ::SetCapture(hwnd); io.MouseDown[button] = true; @@ -272,11 +275,13 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: + case WM_XBUTTONUP: { int button = 0; - if (msg == WM_LBUTTONUP) button = 0; - if (msg == WM_RBUTTONUP) button = 1; - if (msg == WM_MBUTTONUP) button = 2; + if (msg == WM_LBUTTONUP) { button = 0; } + if (msg == WM_RBUTTONUP) { button = 1; } + if (msg == WM_MBUTTONUP) { button = 2; } + if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } io.MouseDown[button] = false; if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) ::ReleaseCapture(); From 295ada036489f1ca226be46f57f6de387979e36e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 17 Jan 2019 18:04:35 +0100 Subject: [PATCH 142/195] Examples: Win32: Using wc.lpszClassName instead of duplicating the literal. + tweak README format. --- examples/README.txt | 24 +++++++++++------------ examples/example_win32_directx10/main.cpp | 6 +++--- examples/example_win32_directx11/main.cpp | 6 +++--- examples/example_win32_directx12/main.cpp | 6 +++--- examples/example_win32_directx9/main.cpp | 8 ++++---- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 1ee91492..3039f821 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -161,61 +161,61 @@ example_win32_directx11/ example_win32_directx12/ DirectX12 example, Windows only. - This is quite long and tedious, because: DirectX12. = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp + This is quite long and tedious, because: DirectX12. example_apple_metal/ OSX & iOS + Metal. + = main.m + imgui_impl_osx.mm + imgui_impl_metal.mm It is based on the "cross-platform" game template provided with Xcode as of Xcode 9. (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.) - = game template + imgui_impl_osx.mm + imgui_impl_metal.mm example_apple_opengl2/ OSX + OpenGL2. - (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.) = main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp + (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.) example_glfw_opengl2/ + GLFW + OpenGL2 example (legacy, fixed pipeline). + = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp **DO NOT USE OPENGL2 CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** **Prefer using OPENGL3 code (with gl3w/glew/glad, you can replace the OpenGL function loader)** - GLFW + OpenGL2 example (legacy, fixed pipeline). This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter. If your code is using GL3+ context or any semi modern OpenGL calls, using this renderer is likely to make things more complicated, will require your code to reset many OpenGL attributes to their initial state, and might confuse your GPU driver. One star, not recommended. - = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp example_glfw_opengl3/ - GLFW (Win32, Mac, Linux) + OpenGL3+/ES2/ES3 example (programmable pipeline, binding modern functions with GL3W). + GLFW (Win32, Mac, Linux) + OpenGL3+/ES2/ES3 example (programmable pipeline). + = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp This uses more modern OpenGL calls and custom shaders. Prefer using that if you are using modern OpenGL in your application (anything with shaders). - = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp example_glfw_vulkan/ GLFW (Win32, Mac, Linux) + Vulkan example. - This is quite long and tedious, because: Vulkan. = main.cpp + imgui_impl_glfw.cpp + imgui_impl_vulkan.cpp + This is quite long and tedious, because: Vulkan. example_sdl_opengl2/ + SDL2 (Win32, Mac, Linux etc.) + OpenGL example (legacy, fixed pipeline). + = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl2.cpp **DO NOT USE OPENGL2 CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** **Prefer using OPENGL3 code (with gl3w/glew/glad, you can replace the OpenGL function loader)** - SDL2 (Win32, Mac, Linux etc.) + OpenGL example (legacy, fixed pipeline). This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter. If your code is using GL3+ context or any semi modern OpenGL calls, using this renderer is likely to make things more complicated, will require your code to reset many OpenGL attributes to their initial state, and might confuse your GPU driver. One star, not recommended. - = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl2.cpp example_sdl_opengl3/ SDL2 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example. + = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl3.cpp This uses more modern OpenGL calls and custom shaders. Prefer using that if you are using modern OpenGL in your application (anything with shaders). - = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl3.cpp example_sdl_vulkan/ SDL2 (Win32, Mac, Linux, etc.) + Vulkan example. - This is quite long and tedious, because: Vulkan. = main.cpp + imgui_impl_sdl.cpp + imgui_impl_vulkan.cpp + This is quite long and tedious, because: Vulkan. example_allegro5/ Allegro 5 example. diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index d6229335..1bd358c1 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -96,13 +96,13 @@ int main(int, char**) // Create application window WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); - HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX10 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); + HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX10 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D if (CreateDeviceD3D(hwnd) < 0) { CleanupDeviceD3D(); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 1; } @@ -218,7 +218,7 @@ int main(int, char**) CleanupDeviceD3D(); DestroyWindow(hwnd); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index eb06ac59..ee5a4eaf 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -99,13 +99,13 @@ int main(int, char**) // Create application window WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); - HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX11 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); + HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX11 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D if (CreateDeviceD3D(hwnd) < 0) { CleanupDeviceD3D(); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 1; } @@ -222,7 +222,7 @@ int main(int, char**) CleanupDeviceD3D(); DestroyWindow(hwnd); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 285fd821..cb5895de 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -272,13 +272,13 @@ int main(int, char**) // Create application window WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); - HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX12 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); + HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX12 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D if (CreateDeviceD3D(hwnd) < 0) { CleanupDeviceD3D(); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 1; } @@ -424,7 +424,7 @@ int main(int, char**) CleanupDeviceD3D(); DestroyWindow(hwnd); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index a7d5173c..0f4c3a25 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -49,13 +49,13 @@ int main(int, char**) // Create application window WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL }; RegisterClassEx(&wc); - HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX9 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); + HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX9 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); // Initialize Direct3D LPDIRECT3D9 pD3D; if ((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) { - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } ZeroMemory(&g_d3dpp, sizeof(g_d3dpp)); @@ -71,7 +71,7 @@ int main(int, char**) if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0) { pD3D->Release(); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } @@ -200,7 +200,7 @@ int main(int, char**) if (g_pd3dDevice) g_pd3dDevice->Release(); if (pD3D) pD3D->Release(); DestroyWindow(hwnd); - UnregisterClass(_T("ImGui Example"), wc.hInstance); + UnregisterClass(wc.lpszClassName, wc.hInstance); return 0; } From 92d29531fa5294e0684969f9dc33126379e6f02d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 18 Jan 2019 11:34:25 +0100 Subject: [PATCH 143/195] Qt links --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index b1e10d53..3fe62445 100644 --- a/docs/README.md +++ b/docs/README.md @@ -149,7 +149,7 @@ Frameworks: - LÖVE+Lua: [love-imgui](https://github.com/slages/love-imgui) - Magnum: [ImGuiIntegration](https://doc.magnum.graphics/magnum/namespaceMagnum_1_1ImGuiIntegration.html) ([example](https://doc.magnum.graphics/magnum/examples-imgui.html)) - NanoRT: [syoyo/imgui](https://github.com/syoyo/imgui/tree/nanort) -- Qt3d: [imgui-qt3d](https://github.com/alpqr/imgui-qt3d), QOpenGLWindow [qtimgui](https://github.com/ocornut/imgui/issues/1910) +- Qt: [imgui-qt3d](https://github.com/alpqr/imgui-qt3d) / [QOpenGLWindow (qtimgui)](https://github.com/ocornut/imgui/issues/1910) / [QtDirect3D](https://github.com/giladreich/QtDirect3D) / [qt6](https://github.com/alpqr/qvk6/tree/imgui/examples/rhi/imguidemo) - SFML: [imgui-sfml](https://github.com/EliasD/imgui-sfml) - Software renderer: [imgui_software_renderer](https://github.com/emilk/imgui_software_renderer) - Unreal Engine 4: [segross/UnrealImGui](https://github.com/segross/UnrealImGui) or [sronsse/UnrealEngine_ImGui](https://github.com/sronsse/UnrealEngine_ImGui) From fcd61e0c5931500299f26afe673e12b527e5960d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 18 Jan 2019 23:02:58 +0100 Subject: [PATCH 144/195] Comments about DLL boundaries and using TLS variables for GImGui. (#2292) --- imgui.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ca4db658..7162997b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1038,11 +1038,19 @@ static void UpdateManualResize(ImGuiWindow* window, const ImVec2& si //----------------------------------------------------------------------------- // Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. -// CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). -// If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file. -// ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can: -// - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 -// - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts) +// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). +// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call +// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. +// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. +// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts, you can: +// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. #ifndef GImGui ImGuiContext* GImGui = NULL; #endif From 8a63c72ac40fb70ef67e843ee8f31ed20eabc24b Mon Sep 17 00:00:00 2001 From: Ryan Mast Date: Sat, 19 Jan 2019 11:45:17 -0800 Subject: [PATCH 145/195] Fix the year for screenshot gallery part 7 and 8 links (#2298) --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 3fe62445..113dd1e4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -175,8 +175,8 @@ User screenshots:
[Gallery Part 4](https://github.com/ocornut/imgui/issues/973) (Jan 2017 to Aug 2017)
[Gallery Part 5](https://github.com/ocornut/imgui/issues/1269) (Aug 2017 to Feb 2018)
[Gallery Part 6](https://github.com/ocornut/imgui/issues/1607) (Feb 2018 to June 2018) -
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 to January 2018) -
[Gallery Part 8](https://github.com/ocornut/imgui/issues/2265) (January 2018 onward) +
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 to January 2019) +
[Gallery Part 8](https://github.com/ocornut/imgui/issues/2265) (January 2019 onward)
Also see the [Mega screenshots](https://github.com/ocornut/imgui/issues/1273) for an idea of the available features. Custom engine From f94ba546bad6a3106603eceb5d2206ee79008463 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 20 Jan 2019 17:45:36 +0100 Subject: [PATCH 146/195] Added checks for "zero-as-null-pointer-constant" warnings for older Clang (#2299, followup to #2277) --- imgui.cpp | 2 ++ imgui.h | 2 ++ imgui_demo.cpp | 2 ++ imgui_draw.cpp | 2 ++ imgui_internal.h | 2 ++ imgui_widgets.cpp | 2 ++ 6 files changed, 12 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 7162997b..93313b19 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -957,7 +957,9 @@ CODE #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // #pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif #if __has_warning("-Wdouble-promotion") #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #endif diff --git a/imgui.h b/imgui.h index fbcf5f44..34745aea 100644 --- a/imgui.h +++ b/imgui.h @@ -77,7 +77,9 @@ Index of this file: #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif #elif defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e3b625ed..06a83ea4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -70,7 +70,9 @@ Index of this file: #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif #if __has_warning("-Wdouble-promotion") #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #endif diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a3c48fc8..caeda567 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -57,7 +57,9 @@ Index of this file: #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif #if __has_warning("-Wcomma") #pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // #endif diff --git a/imgui_internal.h b/imgui_internal.h index 14296b51..52899c89 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -46,7 +46,9 @@ Index of this file: #pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h #pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h #pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif #if __has_warning("-Wdouble-promotion") #pragma clang diagnostic ignored "-Wdouble-promotion" #endif diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ade99fb0..f0eea1ca 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -56,7 +56,9 @@ Index of this file: #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wzero-as-null-pointer-constant") #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif #if __has_warning("-Wdouble-promotion") #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #endif From e837099b671a6544475ef9259b19730091efdcbb Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 20 Jan 2019 17:51:30 +0100 Subject: [PATCH 147/195] Update for stb_ files. (#2038) --- .editorconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 39320baa..3dd05d3d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,7 +11,10 @@ indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true -# Makefile +[imstb_*] +indent_size = 3 +trim_trailing_whitespace = false + [Makefile] indent_style = tab indent_size = 4 From 2c38b32db11459a2a3a32576e230a167f4d70ae7 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 20 Jan 2019 17:56:17 +0100 Subject: [PATCH 148/195] Removed trailing spaces (#2038, #2299) --- examples/example_allegro5/main.cpp | 8 +- .../example_apple_metal/Shared/AppDelegate.h | 1 - .../example_apple_metal/Shared/AppDelegate.m | 1 - .../example_apple_metal/Shared/Renderer.h | 1 - .../example_apple_metal/Shared/Renderer.mm | 9 +- .../Shared/ViewController.h | 1 - .../Shared/ViewController.mm | 13 +- examples/example_apple_metal/Shared/main.m | 1 - examples/example_apple_opengl2/main.mm | 26 ++-- examples/example_freeglut_opengl2/main.cpp | 10 +- examples/example_glfw_opengl2/main.cpp | 8 +- examples/example_glfw_opengl3/main.cpp | 6 +- examples/example_glfw_vulkan/main.cpp | 8 +- examples/example_marmalade/main.cpp | 6 +- examples/example_sdl_opengl2/main.cpp | 6 +- examples/example_sdl_opengl3/main.cpp | 8 +- examples/example_sdl_vulkan/main.cpp | 10 +- examples/example_win32_directx10/main.cpp | 6 +- examples/example_win32_directx11/main.cpp | 6 +- examples/example_win32_directx12/main.cpp | 12 +- examples/example_win32_directx9/main.cpp | 6 +- examples/imgui_impl_dx10.cpp | 8 +- examples/imgui_impl_dx11.cpp | 8 +- examples/imgui_impl_dx12.cpp | 6 +- examples/imgui_impl_dx12.h | 2 +- examples/imgui_impl_dx9.cpp | 2 +- examples/imgui_impl_freeglut.cpp | 2 +- examples/imgui_impl_glfw.cpp | 4 +- examples/imgui_impl_metal.mm | 118 +++++++++--------- examples/imgui_impl_opengl2.cpp | 8 +- examples/imgui_impl_opengl2.h | 2 +- examples/imgui_impl_opengl3.cpp | 2 +- examples/imgui_impl_opengl3.h | 6 +- examples/imgui_impl_osx.mm | 10 +- examples/imgui_impl_sdl.cpp | 6 +- examples/imgui_impl_vulkan.cpp | 12 +- examples/imgui_impl_vulkan.h | 6 +- examples/imgui_impl_win32.cpp | 4 +- imgui.cpp | 94 +++++++------- imgui.h | 42 +++---- imgui_demo.cpp | 72 +++++------ imgui_draw.cpp | 12 +- imgui_internal.h | 8 +- imgui_widgets.cpp | 14 +-- misc/cpp/imgui_stdlib.cpp | 2 +- misc/cpp/imgui_stdlib.h | 2 +- misc/fonts/binary_to_compressed_c.cpp | 10 +- misc/freetype/imgui_freetype.cpp | 16 +-- misc/freetype/imgui_freetype.h | 4 +- 49 files changed, 314 insertions(+), 321 deletions(-) diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp index ddbdf76d..59e19370 100644 --- a/examples/example_allegro5/main.cpp +++ b/examples/example_allegro5/main.cpp @@ -36,8 +36,8 @@ int main(int, char**) ImGui_ImplAllegro5_Init(display); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -67,7 +67,7 @@ int main(int, char**) while (al_get_next_event(queue, &ev)) { ImGui_ImplAllegro5_ProcessEvent(&ev); - if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) + if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) running = false; if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { @@ -96,7 +96,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_apple_metal/Shared/AppDelegate.h b/examples/example_apple_metal/Shared/AppDelegate.h index c4632b1f..94878d94 100644 --- a/examples/example_apple_metal/Shared/AppDelegate.h +++ b/examples/example_apple_metal/Shared/AppDelegate.h @@ -1,4 +1,3 @@ - #import #if TARGET_OS_IPHONE diff --git a/examples/example_apple_metal/Shared/AppDelegate.m b/examples/example_apple_metal/Shared/AppDelegate.m index eabb44c1..6947eb23 100644 --- a/examples/example_apple_metal/Shared/AppDelegate.m +++ b/examples/example_apple_metal/Shared/AppDelegate.m @@ -1,4 +1,3 @@ - #import "AppDelegate.h" @implementation AppDelegate diff --git a/examples/example_apple_metal/Shared/Renderer.h b/examples/example_apple_metal/Shared/Renderer.h index f324915c..81fc6f54 100644 --- a/examples/example_apple_metal/Shared/Renderer.h +++ b/examples/example_apple_metal/Shared/Renderer.h @@ -1,4 +1,3 @@ - #import @interface Renderer : NSObject diff --git a/examples/example_apple_metal/Shared/Renderer.mm b/examples/example_apple_metal/Shared/Renderer.mm index 30ccf5a1..efc3332b 100644 --- a/examples/example_apple_metal/Shared/Renderer.mm +++ b/examples/example_apple_metal/Shared/Renderer.mm @@ -1,4 +1,3 @@ - #import "Renderer.h" #import @@ -50,7 +49,7 @@ io.DeltaTime = 1 / float(view.preferredFramesPerSecond ?: 60); id commandBuffer = [self.commandQueue commandBuffer]; - + static bool show_demo_window = true; static bool show_another_window = false; static float clear_color[4] = { 0.28f, 0.36f, 0.5f, 1.0f }; @@ -87,7 +86,7 @@ ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) @@ -113,13 +112,13 @@ ImGui::Render(); ImDrawData *drawData = ImGui::GetDrawData(); ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder); - + [renderEncoder popDebugGroup]; [renderEncoder endEncoding]; [commandBuffer presentDrawable:view.currentDrawable]; } - + [commandBuffer commit]; } diff --git a/examples/example_apple_metal/Shared/ViewController.h b/examples/example_apple_metal/Shared/ViewController.h index a8aade13..137f93e1 100644 --- a/examples/example_apple_metal/Shared/ViewController.h +++ b/examples/example_apple_metal/Shared/ViewController.h @@ -1,4 +1,3 @@ - #import #import #import "Renderer.h" diff --git a/examples/example_apple_metal/Shared/ViewController.mm b/examples/example_apple_metal/Shared/ViewController.mm index 427c0928..73040add 100644 --- a/examples/example_apple_metal/Shared/ViewController.mm +++ b/examples/example_apple_metal/Shared/ViewController.mm @@ -1,4 +1,3 @@ - #import "ViewController.h" #import "Renderer.h" #include "imgui.h" @@ -21,9 +20,9 @@ - (void)viewDidLoad { [super viewDidLoad]; - + self.mtkView.device = MTLCreateSystemDefaultDevice(); - + if (!self.mtkView.device) { NSLog(@"Metal is not supported"); abort(); @@ -42,7 +41,7 @@ owner:self userInfo:nil]; [self.view addTrackingArea:trackingArea]; - + // If we want to receive key events, we either need to be in the responder chain of the key view, // or else we can install a local monitor. The consequence of this heavy-handed approach is that // we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our @@ -56,9 +55,9 @@ } else { return event; } - + }]; - + ImGui_ImplOSX_Init(); #endif } @@ -97,7 +96,7 @@ CGPoint touchLocation = [anyTouch locationInView:self.view]; ImGuiIO &io = ImGui::GetIO(); io.MousePos = ImVec2(touchLocation.x, touchLocation.y); - + BOOL hasActiveTouch = NO; for (UITouch *touch in event.allTouches) { if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) { diff --git a/examples/example_apple_metal/Shared/main.m b/examples/example_apple_metal/Shared/main.m index cd8468a7..15938a90 100644 --- a/examples/example_apple_metal/Shared/main.m +++ b/examples/example_apple_metal/Shared/main.m @@ -1,4 +1,3 @@ - #import #if TARGET_OS_IPHONE diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index ff179d82..b91cfb96 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -9,7 +9,7 @@ #import #import -//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- // ImGuiExampleView //----------------------------------------------------------------------------------- @@ -29,7 +29,7 @@ -(void)prepareOpenGL { [super prepareOpenGL]; - + #ifndef DEBUG GLint swapInterval = 1; [[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; @@ -65,7 +65,7 @@ ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) @@ -102,7 +102,7 @@ // Present [[self openGLContext] flushBuffer]; - + if (!animationTimer) animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES]; } @@ -174,14 +174,14 @@ { if (_window != nil) return (_window); - + NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 720.0); - + _window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:YES]; [_window setTitle:@"Dear ImGui OSX+OpenGL2 Example"]; [_window setOpaque:YES]; [_window makeKeyAndOrderFront:NSApp]; - + return (_window); } @@ -194,12 +194,12 @@ appMenu = [[NSMenu alloc] initWithTitle:@"Dear ImGui OSX+OpenGL2 Example"]; menuItem = [appMenu addItemWithTitle:@"Quit Dear ImGui OSX+OpenGL2 Example" action:@selector(terminate:) keyEquivalent:@"q"]; [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand]; - + menuItem = [[NSMenuItem alloc] init]; [menuItem setSubmenu:appMenu]; - + [mainMenuBar addItem:menuItem]; - + appMenu = nil; [NSApp setMainMenu:mainMenuBar]; } @@ -217,14 +217,14 @@ // Menu [self setupMenu]; - + NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, 32, 0 }; - + NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; ImGuiExampleView* view = [[ImGuiExampleView alloc] initWithFrame:self.window.frame pixelFormat:format]; format = nil; @@ -233,7 +233,7 @@ [view setWantsBestResolutionOpenGLSurface:YES]; #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 [self.window setContentView:view]; - + if ([view openGLContext] == nil) NSLog(@"No OpenGL Context!"); diff --git a/examples/example_freeglut_opengl2/main.cpp b/examples/example_freeglut_opengl2/main.cpp index 952f3f44..26d548e8 100644 --- a/examples/example_freeglut_opengl2/main.cpp +++ b/examples/example_freeglut_opengl2/main.cpp @@ -32,7 +32,7 @@ void my_display_code() ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) @@ -82,7 +82,7 @@ void glut_display_func() // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. int main(int argc, char** argv) -{ +{ // Create GLUT window glutInit(&argc, argv); glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); @@ -91,7 +91,7 @@ int main(int argc, char** argv) glutCreateWindow("Dear ImGui FreeGLUT+OpenGL2 Example"); // Setup GLUT display function - // We will also call ImGui_ImplFreeGLUT_InstallFuncs() to get all the other functions installed for us, + // We will also call ImGui_ImplFreeGLUT_InstallFuncs() to get all the other functions installed for us, // otherwise it is possible to install our own functions and call the imgui_impl_freeglut.h functions ourselves. glutDisplayFunc(glut_display_func); @@ -110,8 +110,8 @@ int main(int argc, char** argv) ImGui_ImplOpenGL2_Init(); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index db16a883..f12547bf 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -13,7 +13,7 @@ #include // [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers. -// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. +// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. // Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio. #if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) #pragma comment(lib, "legacy_stdio_definitions") @@ -52,8 +52,8 @@ int main(int, char**) ImGui_ImplOpenGL2_Init(); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -100,7 +100,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index dee0dd9d..9888ec5b 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -7,7 +7,7 @@ #include "imgui_impl_opengl3.h" #include -// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. +// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. // Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) @@ -21,10 +21,10 @@ #endif // Include glfw3.h after our OpenGL definitions -#include +#include // [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers. -// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. +// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. // Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio. #if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) #pragma comment(lib, "legacy_stdio_definitions") diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index d6d161b8..fa098af8 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -12,7 +12,7 @@ #include // [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers. -// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. +// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma. // Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio. #if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) #pragma comment(lib, "legacy_stdio_definitions") @@ -376,8 +376,8 @@ int main(int, char**) ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -459,7 +459,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_marmalade/main.cpp b/examples/example_marmalade/main.cpp index f2249acf..e844a4c9 100644 --- a/examples/example_marmalade/main.cpp +++ b/examples/example_marmalade/main.cpp @@ -30,8 +30,8 @@ int main(int, char**) ImGui_Marmalade_Init(true); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -81,7 +81,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index af0d297e..282e5f72 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -49,8 +49,8 @@ int main(int, char**) ImGui_ImplOpenGL2_Init(); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -104,7 +104,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index c28d52cc..3d66cbf2 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -9,7 +9,7 @@ #include #include -// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. +// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. // Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) @@ -89,8 +89,8 @@ int main(int, char**) ImGui_ImplOpenGL3_Init(glsl_version); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -146,7 +146,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index 03993eb4..a7404ec7 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -357,8 +357,8 @@ int main(int, char**) ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -420,7 +420,7 @@ int main(int, char**) ImGui_ImplSDL2_ProcessEvent(&event); if (event.type == SDL_QUIT) done = true; - if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window)) + if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window)) ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2); } @@ -444,7 +444,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) @@ -470,7 +470,7 @@ int main(int, char**) ImGui::Render(); memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); FrameRender(wd); - + FramePresent(wd); } diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 1bd358c1..344af239 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -125,8 +125,8 @@ int main(int, char**) ImGui_ImplDX10_Init(g_pd3dDevice); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -180,7 +180,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index ee5a4eaf..7cfa0abc 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -128,8 +128,8 @@ int main(int, char**) ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -184,7 +184,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index cb5895de..c650d193 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -164,7 +164,7 @@ HRESULT CreateDeviceD3D(HWND hWnd) SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); - for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { g_mainRenderTargetDescriptor[i] = rtvHandle; rtvHandle.ptr += rtvDescriptorSize; @@ -298,14 +298,14 @@ int main(int, char**) // Setup Platform/Renderer bindings ImGui_ImplWin32_Init(hwnd); - ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, + ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, DXGI_FORMAT_R8G8B8A8_UNORM, - g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), + g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -359,7 +359,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index 0f4c3a25..11ef1bac 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -90,8 +90,8 @@ int main(int, char**) ImGui_ImplDX9_Init(g_pd3dDevice); // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'misc/fonts/README.txt' for more instructions and details. @@ -147,7 +147,7 @@ int main(int, char**) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) diff --git a/examples/imgui_impl_dx10.cpp b/examples/imgui_impl_dx10.cpp index ed28f3de..b381d60a 100644 --- a/examples/imgui_impl_dx10.cpp +++ b/examples/imgui_impl_dx10.cpp @@ -8,7 +8,7 @@ // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui -// CHANGELOG +// CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. @@ -311,9 +311,9 @@ bool ImGui_ImplDX10_CreateDeviceObjects() ImGui_ImplDX10_InvalidateDeviceObjects(); // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) - // If you would like to use this DX10 sample code but remove this dependency you can: + // If you would like to use this DX10 sample code but remove this dependency you can: // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] - // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. + // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. // Create the vertex shader @@ -353,7 +353,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects() return false; // Create the input layout - D3D10_INPUT_ELEMENT_DESC local_layout[] = + D3D10_INPUT_ELEMENT_DESC local_layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA, 0 }, diff --git a/examples/imgui_impl_dx11.cpp b/examples/imgui_impl_dx11.cpp index 6fd36d62..f85f5fd2 100644 --- a/examples/imgui_impl_dx11.cpp +++ b/examples/imgui_impl_dx11.cpp @@ -110,7 +110,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) ctx->Unmap(g_pIB, 0); // Setup orthographic projection matrix into our constant buffer - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). { D3D11_MAPPED_SUBRESOURCE mapped_resource; if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) @@ -318,9 +318,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects() ImGui_ImplDX11_InvalidateDeviceObjects(); // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) - // If you would like to use this DX11 sample code but remove this dependency you can: + // If you would like to use this DX11 sample code but remove this dependency you can: // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] - // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. + // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. // Create the vertex shader @@ -360,7 +360,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() return false; // Create the input layout - D3D11_INPUT_ELEMENT_DESC local_layout[] = + D3D11_INPUT_ELEMENT_DESC local_layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, diff --git a/examples/imgui_impl_dx12.cpp b/examples/imgui_impl_dx12.cpp index 490d9e65..6bcaf544 100644 --- a/examples/imgui_impl_dx12.cpp +++ b/examples/imgui_impl_dx12.cpp @@ -144,7 +144,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL g_pIB->Unmap(0, &range); // Setup orthographic projection matrix into our constant buffer - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). VERTEX_CONSTANT_BUFFER vertex_constant_buffer; { VERTEX_CONSTANT_BUFFER* constant_buffer = &vertex_constant_buffer; @@ -437,9 +437,9 @@ bool ImGui_ImplDX12_CreateDeviceObjects() } // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) - // If you would like to use this DX12 sample code but remove this dependency you can: + // If you would like to use this DX12 sample code but remove this dependency you can: // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] - // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. + // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc; diff --git a/examples/imgui_impl_dx12.h b/examples/imgui_impl_dx12.h index 7ead88e6..e5b9dc4e 100644 --- a/examples/imgui_impl_dx12.h +++ b/examples/imgui_impl_dx12.h @@ -19,7 +19,7 @@ struct D3D12_CPU_DESCRIPTOR_HANDLE; struct D3D12_GPU_DESCRIPTOR_HANDLE; // cmd_list is the command list that the implementation will use to render imgui draw lists. -// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate +// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate // render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle. // font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture. IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, diff --git a/examples/imgui_impl_dx9.cpp b/examples/imgui_impl_dx9.cpp index e3e12071..6dd21143 100644 --- a/examples/imgui_impl_dx9.cpp +++ b/examples/imgui_impl_dx9.cpp @@ -8,7 +8,7 @@ // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui -// CHANGELOG +// CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. diff --git a/examples/imgui_impl_freeglut.cpp b/examples/imgui_impl_freeglut.cpp index 2122e307..42d56417 100644 --- a/examples/imgui_impl_freeglut.cpp +++ b/examples/imgui_impl_freeglut.cpp @@ -103,7 +103,7 @@ void ImGui_ImplFreeGLUT_KeyboardFunc(unsigned char c, int x, int y) if (c >= 32) io.AddInputCharacter((unsigned short)c); - // Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26. + // Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26. // This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here. if (c >= 1 && c <= 26) io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = true; diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 4f107115..5f123c88 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -97,7 +97,7 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { - if (g_PrevUserCallbackKey != NULL) + if (g_PrevUserCallbackKey != NULL) g_PrevUserCallbackKey(window, key, scancode, action, mods); ImGuiIO& io = ImGui::GetIO(); @@ -172,7 +172,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); - + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. g_PrevUserCallbackMousebutton = NULL; g_PrevUserCallbackScroll = NULL; diff --git a/examples/imgui_impl_metal.mm b/examples/imgui_impl_metal.mm index 562a01b9..c8373420 100644 --- a/examples/imgui_impl_metal.mm +++ b/examples/imgui_impl_metal.mm @@ -73,7 +73,7 @@ bool ImGui_ImplMetal_Init(id device) dispatch_once(&onceToken, ^{ g_sharedMetalContext = [[MetalContext alloc] init]; }); - + ImGui_ImplMetal_CreateDeviceObjects(device); return true; @@ -100,7 +100,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id bool ImGui_ImplMetal_CreateFontsTexture(id device) { [g_sharedMetalContext makeFontTextureWithDevice:device]; - + ImGuiIO& io = ImGui::GetIO(); io.Fonts->TexID = (__bridge void *)g_sharedMetalContext.fontTexture; // ImTextureID == void* @@ -132,9 +132,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects() #pragma mark - MetalBuffer implementation @implementation MetalBuffer -- (instancetype)initWithBuffer:(id)buffer +- (instancetype)initWithBuffer:(id)buffer { - if ((self = [super init])) + if ((self = [super init])) { _buffer = buffer; _lastReuseTime = [NSDate date].timeIntervalSince1970; @@ -146,9 +146,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects() #pragma mark - FramebufferDescriptor implementation @implementation FramebufferDescriptor -- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor +- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor { - if ((self = [super init])) + if ((self = [super init])) { _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount; _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat; @@ -158,7 +158,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return self; } -- (nonnull id)copyWithZone:(nullable NSZone *)zone +- (nonnull id)copyWithZone:(nullable NSZone *)zone { FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init]; copy.sampleCount = self.sampleCount; @@ -168,7 +168,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return copy; } -- (NSUInteger)hash +- (NSUInteger)hash { NSUInteger sc = _sampleCount & 0x3; NSUInteger cf = _colorPixelFormat & 0x3FF; @@ -178,7 +178,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return hash; } -- (BOOL)isEqual:(id)object +- (BOOL)isEqual:(id)object { FramebufferDescriptor *other = object; if (![other isKindOfClass:[FramebufferDescriptor class]]) @@ -195,7 +195,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() @implementation MetalContext - (instancetype)init { - if ((self = [super init])) + if ((self = [super init])) { _renderPipelineStateCache = [NSMutableDictionary dictionary]; _bufferCache = [NSMutableArray array]; @@ -204,7 +204,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() return self; } -- (void)makeDeviceObjectsWithDevice:(id)device +- (void)makeDeviceObjectsWithDevice:(id)device { MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init]; depthStencilDescriptor.depthWriteEnabled = NO; @@ -216,7 +216,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth. // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures. // You can make that change in your implementation. -- (void)makeFontTextureWithDevice:(id)device +- (void)makeFontTextureWithDevice:(id)device { ImGuiIO &io = ImGui::GetIO(); unsigned char* pixels; @@ -237,17 +237,17 @@ void ImGui_ImplMetal_DestroyDeviceObjects() self.fontTexture = texture; } -- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device +- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device { NSTimeInterval now = [NSDate date].timeIntervalSince1970; - + // Purge old buffers that haven't been useful for a while - if (now - self.lastBufferCachePurge > 1.0) + if (now - self.lastBufferCachePurge > 1.0) { NSMutableArray *survivors = [NSMutableArray array]; - for (MetalBuffer *candidate in self.bufferCache) + for (MetalBuffer *candidate in self.bufferCache) { - if (candidate.lastReuseTime > self.lastBufferCachePurge) + if (candidate.lastReuseTime > self.lastBufferCachePurge) { [survivors addObject:candidate]; } @@ -255,51 +255,51 @@ void ImGui_ImplMetal_DestroyDeviceObjects() self.bufferCache = [survivors mutableCopy]; self.lastBufferCachePurge = now; } - + // See if we have a buffer we can reuse MetalBuffer *bestCandidate = nil; - for (MetalBuffer *candidate in self.bufferCache) + for (MetalBuffer *candidate in self.bufferCache) if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime)) bestCandidate = candidate; - - if (bestCandidate != nil) + + if (bestCandidate != nil) { [self.bufferCache removeObject:bestCandidate]; bestCandidate.lastReuseTime = now; return bestCandidate; } - + // No luck; make a new buffer id backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared]; return [[MetalBuffer alloc] initWithBuffer:backing]; } -- (void)enqueueReusableBuffer:(MetalBuffer *)buffer +- (void)enqueueReusableBuffer:(MetalBuffer *)buffer { [self.bufferCache addObject:buffer]; } -- (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device +- (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device { // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame // Thie hit rate for this cache should be very near 100%. id renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor]; - - if (renderPipelineState == nil) + + if (renderPipelineState == nil) { // No luck; make a new render pipeline state renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device]; // Cache render pipeline state for later reuse self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState; } - + return renderPipelineState; } - (id)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id)device { NSError *error = nil; - + NSString *shaderSource = @"" "#include \n" "using namespace metal;\n" @@ -335,23 +335,23 @@ void ImGui_ImplMetal_DestroyDeviceObjects() " half4 texColor = texture.sample(linearSampler, in.texCoords);\n" " return half4(in.color) * texColor;\n" "}\n"; - + id library = [device newLibraryWithSource:shaderSource options:nil error:&error]; - if (library == nil) + if (library == nil) { NSLog(@"Error: failed to create Metal library: %@", error); return nil; } - + id vertexFunction = [library newFunctionWithName:@"vertex_main"]; id fragmentFunction = [library newFunctionWithName:@"fragment_main"]; - - if (vertexFunction == nil || fragmentFunction == nil) + + if (vertexFunction == nil || fragmentFunction == nil) { NSLog(@"Error: failed to find Metal shader functions in library: %@", error); return nil; } - + MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor]; vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos); vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position @@ -365,7 +365,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() vertexDescriptor.layouts[0].stepRate = 1; vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex; vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert); - + MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init]; pipelineDescriptor.vertexFunction = vertexFunction; pipelineDescriptor.fragmentFunction = fragmentFunction; @@ -381,17 +381,17 @@ void ImGui_ImplMetal_DestroyDeviceObjects() pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat; pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat; - + id renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; - if (error != nil) + if (error != nil) { NSLog(@"Error: failed to create Metal pipeline state: %@", error); } - + return renderPipelineState; } -- (void)emptyRenderPipelineStateCache +- (void)emptyRenderPipelineStateCache { [self.renderPipelineStateCache removeAllObjects]; } @@ -407,21 +407,21 @@ void ImGui_ImplMetal_DestroyDeviceObjects() if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0) return; drawData->ScaleClipRects(io.DisplayFramebufferScale); - + [commandEncoder setCullMode:MTLCullModeNone]; [commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState]; - + // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps. - MTLViewport viewport = - { + MTLViewport viewport = + { .originX = 0.0, .originY = 0.0, .width = double(fb_width), .height = double(fb_height), .znear = 0.0, - .zfar = 1.0 + .zfar = 1.0 }; [commandEncoder setViewport:viewport]; float L = drawData->DisplayPos.x; @@ -437,26 +437,26 @@ void ImGui_ImplMetal_DestroyDeviceObjects() { 0.0f, 0.0f, 1/(F-N), 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f }, }; - + [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1]; - + size_t vertexBufferLength = 0; size_t indexBufferLength = 0; - for (int n = 0; n < drawData->CmdListsCount; n++) + for (int n = 0; n < drawData->CmdListsCount; n++) { const ImDrawList* cmd_list = drawData->CmdLists[n]; vertexBufferLength += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); indexBufferLength += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); } - + MetalBuffer *vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device]; MetalBuffer *indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device]; - + id renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device]; [commandEncoder setRenderPipelineState:renderPipelineState]; - + [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0]; - + size_t vertexBufferOffset = 0; size_t indexBufferOffset = 0; ImVec2 pos = drawData->DisplayPos; @@ -464,12 +464,12 @@ void ImGui_ImplMetal_DestroyDeviceObjects() { const ImDrawList* cmd_list = drawData->CmdLists[n]; ImDrawIdx idx_buffer_offset = 0; - + memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - + [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0]; - + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; @@ -489,8 +489,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() .width = NSUInteger(clip_rect.z - clip_rect.x), .height = NSUInteger(clip_rect.w - clip_rect.y) }; [commandEncoder setScissorRect:scissorRect]; - - + + // Bind texture, Draw if (pcmd->TextureId != NULL) [commandEncoder setFragmentTexture:(__bridge id)(pcmd->TextureId) atIndex:0]; @@ -503,13 +503,13 @@ void ImGui_ImplMetal_DestroyDeviceObjects() } idx_buffer_offset += pcmd->ElemCount * sizeof(ImDrawIdx); } - + vertexBufferOffset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); indexBufferOffset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); } - + __weak id weakSelf = self; - [commandBuffer addCompletedHandler:^(id) + [commandBuffer addCompletedHandler:^(id) { dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf enqueueReusableBuffer:vertexBuffer]; diff --git a/examples/imgui_impl_opengl2.cpp b/examples/imgui_impl_opengl2.cpp index 7b9d2b80..057f8539 100644 --- a/examples/imgui_impl_opengl2.cpp +++ b/examples/imgui_impl_opengl2.cpp @@ -13,10 +13,10 @@ // This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might -// confuse your GPU driver. +// confuse your GPU driver. // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. -// CHANGELOG +// CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications. @@ -72,7 +72,7 @@ void ImGui_ImplOpenGL2_NewFrame() // OpenGL2 Render function. // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) -// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. +// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) @@ -88,7 +88,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); - GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/examples/imgui_impl_opengl2.h b/examples/imgui_impl_opengl2.h index e901cb7b..2e3271dc 100644 --- a/examples/imgui_impl_opengl2.h +++ b/examples/imgui_impl_opengl2.h @@ -13,7 +13,7 @@ // This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might -// confuse your GPU driver. +// confuse your GPU driver. // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. #pragma once diff --git a/examples/imgui_impl_opengl3.cpp b/examples/imgui_impl_opengl3.cpp index 917fa809..14a8964a 100644 --- a/examples/imgui_impl_opengl3.cpp +++ b/examples/imgui_impl_opengl3.cpp @@ -76,7 +76,7 @@ #include // Use GL ES 3 #else // Regular OpenGL -// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. +// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. // Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) diff --git a/examples/imgui_impl_opengl3.h b/examples/imgui_impl_opengl3.h index fba03d0b..0be9dcd8 100644 --- a/examples/imgui_impl_opengl3.h +++ b/examples/imgui_impl_opengl3.h @@ -9,9 +9,9 @@ // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui -// About OpenGL function loaders: -// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. -// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. +// About OpenGL function loaders: +// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. +// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. // About GLSL version: diff --git a/examples/imgui_impl_osx.mm b/examples/imgui_impl_osx.mm index 39f706c8..07381caf 100644 --- a/examples/imgui_impl_osx.mm +++ b/examples/imgui_impl_osx.mm @@ -53,14 +53,14 @@ bool ImGui_ImplOSX_Init() io.KeyMap[ImGuiKey_X] = 'X'; io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Z] = 'Z'; - + io.SetClipboardTextFn = [](void*, const char* str) -> void { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString]; }; - + io.GetClipboardTextFn = [](void*) -> const char* { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; @@ -71,7 +71,7 @@ bool ImGui_ImplOSX_Init() NSString* string = [pasteboard stringForType:NSPasteboardTypeString]; if (string == nil) return NULL; - + const char* string_c = (const char*)[string UTF8String]; size_t string_len = strlen(string_c); static ImVector s_clipboard; @@ -79,7 +79,7 @@ bool ImGui_ImplOSX_Init() strcpy(s_clipboard.Data, string_c); return s_clipboard.Data; }; - + return true; } @@ -235,6 +235,6 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) resetKeys(); return io.WantCaptureKeyboard; } - + return false; } diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 54ddc282..c1188dba 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -23,14 +23,14 @@ // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. // 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples. -// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter. +// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter. // 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText). // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. // 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. // 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS). -// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes. +// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes. // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. // 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS. // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. @@ -238,7 +238,7 @@ static void ImGui_ImplSDL2_UpdateMousePosAndButtons() io.MousePos = ImVec2((float)mx, (float)my); } - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. + // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. // The function is only supported from SDL 2.0.4 (released Jan 2016) bool any_mouse_button_down = ImGui::IsAnyMouseDown(); SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index dbfbe5ca..14807863 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -8,7 +8,7 @@ // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui -// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. +// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ // CHANGELOG @@ -310,7 +310,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here? vkCmdSetScissor(command_buffer, 0, 1, &scissor); - + // Draw vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); } @@ -735,11 +735,11 @@ void ImGui_ImplVulkan_NewFrame() //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers //------------------------------------------------------------------------- -// You probably do NOT need to use or care about those functions. +// You probably do NOT need to use or care about those functions. // Those functions only exist because: // 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. // 2) the upcoming multi-viewport feature will need them internally. -// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, +// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, // but it is too much code to duplicate everywhere so we exceptionally expose them. // Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). // You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. @@ -808,7 +808,7 @@ VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physic } else { - // Request several formats, the first found will be used + // Request several formats, the first found will be used for (int request_i = 0; request_i < request_formats_count; request_i++) for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) if (avail_format[avail_i].format == request_formats[request_i] && avail_format[avail_i].colorSpace == request_color_space) @@ -919,7 +919,7 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice wd->BackBufferCount = 0; if (wd->RenderPass) vkDestroyRenderPass(device, wd->RenderPass, allocator); - + // If min image count was not specified, request different count of images dependent on selected present mode if (min_image_count == 0) min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode); diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h index eda25ef9..0a01bc0e 100644 --- a/examples/imgui_impl_vulkan.h +++ b/examples/imgui_impl_vulkan.h @@ -8,7 +8,7 @@ // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui -// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. +// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ #pragma once @@ -47,11 +47,11 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects(); //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers //------------------------------------------------------------------------- -// You probably do NOT need to use or care about those functions. +// You probably do NOT need to use or care about those functions. // Those functions only exist because: // 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. // 2) the upcoming multi-viewport feature will need them internally. -// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, +// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, // but it is too much code to duplicate everywhere so we exceptionally expose them. // Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). // You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 616ee06a..83c20c05 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -34,7 +34,7 @@ // 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert. // 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag. // 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read. -// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging. +// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging. // 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set. // Win32 Data @@ -242,7 +242,7 @@ void ImGui_ImplWin32_NewFrame() #define DBT_DEVNODES_CHANGED 0x0007 #endif -// Process Win32 mouse/keyboard inputs. +// Process Win32 mouse/keyboard inputs. // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. diff --git a/imgui.cpp b/imgui.cpp index 93313b19..abd29eed 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -40,19 +40,19 @@ DOCUMENTATION - How can I tell whether to dispatch mouse/keyboard to imgui or to my application? - How can I display an image? What is ImTextureID, how does it works? - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack. - - How can I use my own math types instead of ImVec2/ImVec4? + - How can I use my own math types instead of ImVec2/ImVec4? - How can I load a different font than the default? - How can I easily use icons in my application? - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? - - How can I interact with standard C++ types (such as std::string and std::vector)? + - How can I interact with standard C++ types (such as std::string and std::vector)? - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad) - I integrated Dear ImGui in my engine and the text or lines are blurry.. - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - How can I help? -CODE +CODE (search for "[SECTION]" in the code to find them) // [SECTION] FORWARD DECLARATIONS @@ -205,7 +205,7 @@ CODE ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); g_pSwapChain->Present(1, 0); } - + // Shutdown ImGui_ImplDX11_Shutdown(); ImGui_ImplWin32_Shutdown(); @@ -276,7 +276,7 @@ CODE // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) @@ -297,7 +297,7 @@ CODE // (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), + // 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. // - 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; @@ -314,13 +314,13 @@ CODE - The examples/ folders contains many actual implementation of the pseudo-codes above. - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated. - They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs + They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information. - Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues! USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS - - The gamepad/keyboard navigation is fairly functional and keeps being improved. + - The gamepad/keyboard navigation is fairly functional and keeps being improved. - Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse! - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. @@ -370,7 +370,7 @@ CODE - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). - - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. + - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp. @@ -387,7 +387,7 @@ CODE old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant. when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. - - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. + - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. @@ -567,7 +567,7 @@ CODE A: Short explanation: - You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures. - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value. - - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason). + - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason). Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward. Long explanation: @@ -575,10 +575,10 @@ CODE At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.). - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API. - We carry the information to identify a "texture" in the ImTextureID type. + We carry the information to identify a "texture" in the ImTextureID type. ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice. Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function. - - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying + - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying an image from the end-user perspective. This is what the _examples_ rendering functions are using: OpenGL: ImTextureID = GLuint (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp) @@ -586,13 +586,13 @@ CODE DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp) DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp) - For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID. - Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure + For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID. + Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure tying together both the texture and information about its format and how to read it. - If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them. - If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID + If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID representation suggested by the example bindings is probably the best choice. (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer) @@ -600,7 +600,7 @@ CODE // Cast our texture type to ImTextureID / void* MyTexture* texture = g_CoffeeTableTexture; - ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height)); + ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height)); The renderer function called after ImGui::Render() will receive that same value that the user code passed: @@ -633,7 +633,7 @@ CODE // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it: ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height)); - C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa. + C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa. Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTexture / void*. Examples: @@ -655,7 +655,7 @@ CODE Dear ImGui internally need to uniquely identify UI elements. Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. - Interactive widgets (such as calls to Button buttons) need a unique ID. + Interactive widgets (such as calls to Button buttons) need a unique ID. Unique ID are used internally to track active widgets and occasionally associate state to widgets. Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element. @@ -765,7 +765,7 @@ CODE e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. See what makes more sense in your situation! - Q: How can I use my own math types instead of ImVec2/ImVec4? + Q: How can I use my own math types instead of ImVec2/ImVec4? A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions. This way you'll be able to use your own types everywhere, e.g. passsing glm::vec2 to ImGui functions instead of ImVec2. @@ -775,7 +775,7 @@ CODE io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code. - (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.) + (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.) (Read the 'misc/fonts/README.txt' file for more details about font loading.) New programmers: remember that in C/C++ and most programming languages if you want to use a @@ -786,7 +786,7 @@ CODE Q: How can I easily use icons in my application? A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you - main font. Then you can refer to icons within your strings. + main font. Then you can refer to icons within your strings. You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment. (Read the 'misc/fonts/README.txt' file for more details about icons font loading.) @@ -838,14 +838,14 @@ CODE (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work! Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. - Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter(). - The applications in examples/ are doing that. + Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter(). + The applications in examples/ are doing that. Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode). You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state. - Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for + Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly. - Q: How can I interact with standard C++ types (such as std::string and std::vector)? + Q: How can I interact with standard C++ types (such as std::string and std::vector)? A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers), and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases. @@ -853,18 +853,18 @@ CODE - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API. Prefer using them over the old and awkward Combo()/ListBox() api. - - Generally for most high-level types you should be able to access the underlying data type. + - Generally for most high-level types you should be able to access the underlying data type. You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code). - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application. Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances. - Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those - are not configurable and not the same across implementations. - - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount + Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those + are not configurable and not the same across implementations. + - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern - is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead. + is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead. One possible implementation of a helper to facilitate printf-style building of strings: https://github.com/ocornut/Str - This is a small helper where you can instance strings with configurable local buffers length. Many game engines will + This is a small helper where you can instance strings with configurable local buffers length. Many game engines will provide similar or better string helpers. Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) @@ -872,21 +872,21 @@ CODE (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse) Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows. - - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create + - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData, and then call your rendered code with your own ImDrawList or ImDrawData data. Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls". (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad) - - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy) - This is the preferred solution for developer productivity. + - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy) + This is the preferred solution for developer productivity. In particular, the "micro-synergy-client" repository (https://github.com/symless/micro-synergy-client) has simple - and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect + and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer. Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols. - - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends + - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine. - - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate + - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing for screen real-estate and precision. @@ -899,7 +899,7 @@ CODE Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). Q: How can I help? - A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt + A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt and see how you want to help and can help! - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui. - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README. @@ -1044,7 +1044,7 @@ static void UpdateManualResize(ImGuiWindow* window, const ImVec2& si // 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call // SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. // In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. -// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. +// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. // If you want thread-safety to allow N threads to access N different contexts, you can: // - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: // struct ImGuiContext; @@ -2909,7 +2909,7 @@ void* ImGui::MemAlloc(size_t size) void ImGui::MemFree(void* ptr) { - if (ptr) + if (ptr) if (ImGuiContext* ctx = GImGui) ctx->IO.MetricsActiveAllocations--; return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); @@ -3907,8 +3907,8 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items } // Find window given position, search front-to-back -// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically -// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is +// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically +// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is // called, aka before the next Begin(). Moving window isn't affected. static void FindHoveredWindow() { @@ -6734,8 +6734,8 @@ void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under) // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely. // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing. - // The current code will set focus to the parent of the popup window which is incorrect. - // It rarely manifested until now because UpdateMouseMovingWindow() would call FocusWindow() again on the clicked window, + // The current code will set focus to the parent of the popup window which is incorrect. + // It rarely manifested until now because UpdateMouseMovingWindow() would call FocusWindow() again on the clicked window, // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again. // However if the clicked window has the _NoMove flag set we would be left with B focused. // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway, @@ -7949,7 +7949,7 @@ static void ImGui::NavUpdateWindowing() { // Move to parent menu if necessary ImGuiWindow* new_nav_window = g.NavWindow; - while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 + while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) new_nav_window = new_nav_window->ParentWindow; @@ -8427,7 +8427,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) { // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) - // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. BeginTooltip(); if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) { diff --git a/imgui.h b/imgui.h index 34745aea..81a6260c 100644 --- a/imgui.h +++ b/imgui.h @@ -228,11 +228,11 @@ namespace ImGui // Windows // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. // - You may append multiple times to the same window during the same frame. - // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, + // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, // which clicking will set the boolean to false when clicked. // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! - // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. + // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.] // - Note that the bottom of window stack always contains a window called "Debug". IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); @@ -321,7 +321,7 @@ namespace ImGui IMGUI_API void PopButtonRepeat(); // Cursor / Layout - // - By "cursor" we mean the current output position. + // - By "cursor" we mean the current output position. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. @@ -337,7 +337,7 @@ namespace ImGui IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) - IMGUI_API void SetCursorPosY(float local_y); // + 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] @@ -485,7 +485,7 @@ namespace ImGui IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header // Widgets: Selectables - // - A selectable highlights when hovered, and can display another color when selected. + // - A selectable highlights when hovered, and can display another color when selected. // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height 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. @@ -504,7 +504,7 @@ namespace ImGui 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)); IMGUI_API void PlotHistogram(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)); - // Widgets: Value() Helpers. + // Widgets: Value() Helpers. // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) IMGUI_API void Value(const char* prefix, bool b); IMGUI_API void Value(const char* prefix, int v); @@ -584,7 +584,7 @@ namespace ImGui IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. - + // Clipping IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); IMGUI_API void PopClipRect(); @@ -654,8 +654,8 @@ namespace ImGui IMGUI_API void ResetMouseDragDelta(int button = 0); // IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type - IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. - IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. + IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. + IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) IMGUI_API const char* GetClipboardText(); @@ -814,7 +814,7 @@ enum ImGuiTabBarFlags_ ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown -}; +}; // Flags for ImGui::BeginTabItem() enum ImGuiTabItemFlags_ @@ -1161,7 +1161,7 @@ enum ImGuiCond_ // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. // Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. -// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, // do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. //----------------------------------------------------------------------------- @@ -1221,7 +1221,7 @@ struct ImVector //----------------------------------------------------------------------------- // ImGuiStyle // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). -// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, +// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, // and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. //----------------------------------------------------------------------------- @@ -1250,7 +1250,7 @@ struct ImGuiStyle float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. - float TabBorderSize; // Thickness of border around tabs. + float TabBorderSize; // Thickness of border around tabs. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! @@ -1266,7 +1266,7 @@ struct ImGuiStyle //----------------------------------------------------------------------------- // ImGuiIO -// Communicate most settings and inputs/outputs to Dear ImGui using this structure. +// Communicate most settings and inputs/outputs to Dear ImGui using this structure. // Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. //----------------------------------------------------------------------------- @@ -1354,7 +1354,7 @@ struct ImGuiIO float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). // Functions - IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input + IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually @@ -1412,7 +1412,7 @@ struct ImGuiIO // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows // - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. -// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. struct ImGuiInputTextCallbackData { ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only @@ -1716,7 +1716,7 @@ struct ImColor // Draw callbacks for advanced uses. // NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, -// you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state, +// you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state, // B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. // The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); @@ -1966,13 +1966,13 @@ enum ImFontAtlasFlags_ // - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. // - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) -// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. // This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. // Common pitfalls: -// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. // - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. -// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, +// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, // - Even though many functions are suffixed with "TTF", OTF data is supported just as well. // - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! struct ImFontAtlas @@ -1993,7 +1993,7 @@ struct ImFontAtlas // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). // The pitch is always = Width * BytesPerPixels (1 or 4) - // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 06a83ea4..9da96813 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3,22 +3,22 @@ // Message to the person tempted to delete this file when integrating Dear ImGui into their code base: // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders -// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of -// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team, +// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of +// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team, // likely leading you to poorer usage of the library. // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). -// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked, +// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked, // you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. // In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. // Thank you, // -Your beloved friend, imgui_demo.cpp (that you won't delete) -// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: -// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is -// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data +// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: +// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is +// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data // in the same place, to make the demo source code faster to read, faster to write, and smaller in size. // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant -// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is +// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is // likely going to be stored outside your functions. /* @@ -421,7 +421,7 @@ static void ShowDemoWindowWidgets() // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. for (int i = 0; i < 7; i++) { - if (i > 0) + if (i > 0) ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); @@ -915,7 +915,7 @@ static void ShowDemoWindowWidgets() if (ImGui::TreeNode("Multi-line Text Input")) { - // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize + // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. static bool read_only = false; static char text[1024*16] = @@ -1152,15 +1152,15 @@ static void ShowDemoWindowWidgets() if (ImGui::TreeNode("Data Types")) { // The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double - // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type, - // and passing all arguments by address. + // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type, + // and passing all arguments by address. // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. - // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it - // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address + // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it + // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address // to the generic function. For example: - // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") - // { - // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + // { + // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); // } // Limits (as helper variables that we can take the address of) @@ -1355,7 +1355,7 @@ static void ShowDemoWindowWidgets() static int mode = 0; if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); - if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } + if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" }; for (int n = 0; n < IM_ARRAYSIZE(names); n++) { @@ -1500,7 +1500,7 @@ static void ShowDemoWindowWidgets() if (embed_all_inside_a_child_window) ImGui::EndChild(); - // Calling IsItemHovered() after begin returns the hovered status of the title bar. + // Calling IsItemHovered() after begin returns the hovered status of the title bar. // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. static bool test_window = false; ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); @@ -2026,7 +2026,7 @@ static void ShowDemoWindowPopups() // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. - // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. + // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. if (ImGui::TreeNode("Popups")) { @@ -2122,7 +2122,7 @@ static void ShowDemoWindowPopups() ImGui::Text("(You can also right-click me to the same popup as above.)"); ImGui::OpenPopupOnItemClick("item context menu", 1); - // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). + // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). // BeginPopupContextItem() will use the last item ID as the popup ID. // In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details) static char name[32] = "Label1"; @@ -3385,10 +3385,10 @@ struct ExampleAppLog ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines bool ScrollToBottom; - void Clear() - { - Buf.clear(); - LineOffsets.clear(); + void Clear() + { + Buf.clear(); + LineOffsets.clear(); LineOffsets.push_back(0); } @@ -3438,11 +3438,11 @@ struct ExampleAppLog else { // The simplest and easy way to display the entire buffer: - // ImGui::TextUnformatted(buf_begin, buf_end); + // ImGui::TextUnformatted(buf_begin, buf_end); // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines. // Here we instead demonstrate using the clipper to only process lines that are within the visible area. // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended. - // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, + // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height, // both of which we can handle since we an array pointing to the beginning of each line of text. // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper. // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries) @@ -3485,7 +3485,7 @@ static void ShowExampleAppLog(bool* p_open) { const char* categories[3] = { "info", "warn", "error" }; const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; - log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]); counter++; } @@ -3952,16 +3952,16 @@ struct MyDocument bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo) bool OpenPrev; // Copy of Open from last update. bool Dirty; // Set when the document has been modified - bool WantClose; // Set when the document + bool WantClose; // Set when the document ImVec4 Color; // An arbitrary variable associated to the document MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) - { - Name = name; - Open = OpenPrev = open; - Dirty = false; - WantClose = false; - Color = color; + { + Name = name; + Open = OpenPrev = open; + Dirty = false; + WantClose = false; + Color = color; } void DoOpen() { Open = true; } void DoQueueClose() { WantClose = true; } @@ -4018,8 +4018,8 @@ struct ExampleAppDocuments // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed -// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. -// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar +// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. +// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar // will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame. // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index caeda567..bd44e159 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -958,7 +958,7 @@ void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, floa return; } - // Note that we are adding a point at both a_min and 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! _Path.reserve(_Path.Size + (num_segments + 1)); for (int i = 0; i <= num_segments; i++) @@ -1848,7 +1848,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) continue; if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? continue; - + // Add to avail set/counters src_tmp.GlyphsCount++; dst_tmp.GlyphsCount++; @@ -2019,7 +2019,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) float char_off_x = font_off_x; if (char_advance_x_org != char_advance_x_mod) char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; - + // Register glyph stbtt_aligned_quad q; float dummy_x = 0.0f, dummy_y = 0.0f; @@ -2300,7 +2300,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16, 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2, 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65, - 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, + 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, }; static ImWchar base_ranges[] = // not zero-terminated { @@ -3049,8 +3049,8 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im draw_list->PathFillConvex(col); } -// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, -// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match +// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, +// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match // the boldness or positioning of what the font uses... void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) { diff --git a/imgui_internal.h b/imgui_internal.h index 52899c89..47bb9385 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -358,9 +358,9 @@ enum ImGuiItemStatusFlags_ #ifdef IMGUI_ENABLE_TEST_ENGINE , // [imgui-test only] - ImGuiItemStatusFlags_Openable = 1 << 10, // - ImGuiItemStatusFlags_Opened = 1 << 11, // - ImGuiItemStatusFlags_Checkable = 1 << 12, // + ImGuiItemStatusFlags_Openable = 1 << 10, // + ImGuiItemStatusFlags_Opened = 1 << 11, // + ImGuiItemStatusFlags_Checkable = 1 << 12, // ImGuiItemStatusFlags_Checked = 1 << 13 // #endif }; @@ -1430,7 +1430,7 @@ namespace ImGui IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging IMGUI_API void TreePushRawID(ImGuiID id); - // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. + // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, const T v_min, const T v_max, const char* format, float power, ImGuiDragFlags flags); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f0eea1ca..dd92c452 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1458,7 +1458,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* const items[ return value_changed; } -// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" +// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) { int items_count = 0; @@ -3123,7 +3123,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // Edit a string of text // - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". -// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match +// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match // Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. // - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. // - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h @@ -3149,7 +3149,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! - if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, BeginGroup(); const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -4610,7 +4610,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl // - TreeNodeV() // - TreeNodeEx() // - TreeNodeExV() -// - TreeNodeBehavior() [Internal] +// - TreeNodeBehavior() [Internal] // - TreePush() // - TreePop() // - TreeAdvanceToLabelPos() @@ -5869,7 +5869,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG return true; } - // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. + // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); @@ -5884,7 +5884,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; tab_bar->CurrFrameVisible = g.FrameCount; - // Layout + // Layout ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); window->DC.CursorPos.x = tab_bar->BarRect.Min.x; @@ -5998,7 +5998,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) found_selected_tab_id = true; // Refresh tab width immediately if we can (for manual tab bar, WidthContent will lag by one frame which is mostly noticeable when changing style.FramePadding.x) - // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, + // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; diff --git a/misc/cpp/imgui_stdlib.cpp b/misc/cpp/imgui_stdlib.cpp index 790d8d80..694813a4 100644 --- a/misc/cpp/imgui_stdlib.cpp +++ b/misc/cpp/imgui_stdlib.cpp @@ -3,7 +3,7 @@ // This is also an example of how you may wrap your own similar types. // Compatibility: -// - std::string support is only guaranteed to work from C++11. +// - std::string support is only guaranteed to work from C++11. // If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) // Changelog: diff --git a/misc/cpp/imgui_stdlib.h b/misc/cpp/imgui_stdlib.h index 200c45a5..06b06b9a 100644 --- a/misc/cpp/imgui_stdlib.h +++ b/misc/cpp/imgui_stdlib.h @@ -3,7 +3,7 @@ // This is also an example of how you may wrap your own similar types. // Compatibility: -// - std::string support is only guaranteed to work from C++11. +// - std::string support is only guaranteed to work from C++11. // If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) // Changelog: diff --git a/misc/fonts/binary_to_compressed_c.cpp b/misc/fonts/binary_to_compressed_c.cpp index 08b102d4..3fde3d95 100644 --- a/misc/fonts/binary_to_compressed_c.cpp +++ b/misc/fonts/binary_to_compressed_c.cpp @@ -56,7 +56,7 @@ int main(int argc, char** argv) return binary_to_compressed_c(argv[argn], argv[argn+1], use_base85_encoding, use_compression) ? 0 : 1; } -char Encode85Byte(unsigned int x) +char Encode85Byte(unsigned int x) { x = (x % 85) + 35; return (x>='\\') ? x+1 : x; @@ -214,7 +214,7 @@ static int stb__window = 0x40000; // 256K static int stb_not_crap(int best, int dist) { - return ((best > 2 && dist <= 0x00100) + return ((best > 2 && dist <= 0x00100) || (best > 5 && dist <= 0x04000) || (best > 7 && dist <= 0x80000)); } @@ -296,15 +296,15 @@ static int stb_compress_chunk(stb_uchar *history, stb_out(dist-1); } else if (best > 5 && best <= 0x100 && dist <= 0x4000) { outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out2(0x4000 + dist-1); + stb_out2(0x4000 + dist-1); stb_out(best-1); } else if (best > 7 && best <= 0x100 && dist <= 0x80000) { outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out3(0x180000 + dist-1); + stb_out3(0x180000 + dist-1); stb_out(best-1); } else if (best > 8 && best <= 0x10000 && dist <= 0x80000) { outliterals(lit_start, q-lit_start); lit_start = (q += best); - stb_out3(0x100000 + dist-1); + stb_out3(0x100000 + dist-1); stb_out2(best-1); } else if (best > 9 && dist <= 0x1000000) { if (best > 65536) best = 65536; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index cef5a716..a4a18119 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -38,7 +38,7 @@ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #endif -namespace +namespace { // Glyph metrics: // -------------- @@ -72,7 +72,7 @@ namespace // |------------- advanceX ----------->| /// A structure that describe a glyph. - struct GlyphInfo + struct GlyphInfo { int Width; // Glyph's width in pixels. int Height; // Glyph's height in pixels. @@ -139,7 +139,7 @@ namespace LoadFlags |= FT_LOAD_TARGET_LIGHT; else if (UserFlags & ImGuiFreeType::MonoHinting) LoadFlags |= FT_LOAD_TARGET_MONO; - else + else LoadFlags |= FT_LOAD_TARGET_NORMAL; return true; @@ -147,16 +147,16 @@ namespace void FreeTypeFont::CloseFont() { - if (Face) + if (Face) { FT_Done_Face(Face); Face = NULL; } } - void FreeTypeFont::SetPixelHeight(int pixel_height) + void FreeTypeFont::SetPixelHeight(int pixel_height) { - // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' + // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. // NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result. FT_Size_RequestRec req; @@ -391,7 +391,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns buf_rects.resize(total_glyphs_count); memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); - // Allocate temporary rasterization data buffers. + // Allocate temporary rasterization data buffers. // We could not find a way to retrieve accurate glyph size without rendering them. // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform) // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations. @@ -539,7 +539,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns float char_off_x = font_off_x; if (char_advance_x_org != char_advance_x_mod) char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; - + // Register glyph float x0 = info.OffsetX + char_off_x; float y0 = info.OffsetY + font_off_y; diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index a0503bff..9df5780e 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -12,10 +12,10 @@ namespace ImGuiFreeType // When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output. // The Default hinting mode usually looks good, but may distort glyphs in an unusual way. // The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. - + // You can set those flags on a per font basis in ImFontConfig::RasterizerFlags. // Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts. - enum RasterizerFlags + enum RasterizerFlags { // By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. From 259f3c78a20797640db225a349de9ccd0eb80a0d Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 20 Jan 2019 18:10:52 +0100 Subject: [PATCH 149/195] Examples: OpenGL2: Added (yet another) comment/instruction against using opengl2 with modern OpenGL. (#2297) --- examples/example_glfw_opengl2/main.cpp | 8 +++++++- examples/imgui_impl_opengl2.cpp | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index f12547bf..eae7ed78 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -129,8 +129,14 @@ int main(int, char**) glViewport(0, 0, display_w, display_h); glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); - //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound, but prefer using the GL3+ code. + + // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), + // you may need to backup/reset/restore current shader using the commented lines below. + //GLint last_program; + //glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); + //glUseProgram(0); ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); + //glUseProgram(last_program); glfwMakeContextCurrent(window); glfwSwapBuffers(window); diff --git a/examples/imgui_impl_opengl2.cpp b/examples/imgui_impl_opengl2.cpp index 057f8539..9745238c 100644 --- a/examples/imgui_impl_opengl2.cpp +++ b/examples/imgui_impl_opengl2.cpp @@ -102,7 +102,14 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) glEnableClientState(GL_COLOR_ARRAY); glEnable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound + + // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!), + // you may need to backup/reset/restore current shader using the lines below. DO NOT MODIFY THIS FILE! Add the code in your calling function: + // GLint last_program; + // glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); + // glUseProgram(0); + // ImGui_ImplOpenGL2_RenderDrawData(...); + // glUseProgram(last_program) // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps. From 00ffdb9fa9729f6a7690ab685cddc295dc237ce6 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 20 Jan 2019 22:21:26 +0100 Subject: [PATCH 150/195] ImGuiTextBuffer: Added append() function (unformatted). --- docs/CHANGELOG.txt | 1 + imgui.cpp | 38 ++++++++++++++++++++++++++++---------- imgui.h | 1 + 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6b3f8775..44146071 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,6 +37,7 @@ Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] +- ImGuiTextBuffer: Added append() function (unformatted). - ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093) - ImFontAtlas: FreeType: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] - Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created diff --git a/imgui.cpp b/imgui.cpp index abd29eed..d00f46dc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2097,6 +2097,32 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const char ImGuiTextBuffer::EmptyString[1] = { 0 }; +void ImGuiTextBuffer::append(const char* str, const char* str_end) +{ + int len = str_end ? (int)(str_end - str) : (int)strlen(str); + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + memcpy(&Buf[write_off - 1], str, (size_t)len); + Buf[write_off - 1 + len] = 0; +} + +void ImGuiTextBuffer::appendf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + appendfv(fmt, args); + va_end(args); +} + // Helper: Text buffer for logging/accumulating text void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) { @@ -2115,8 +2141,8 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) const int needed_sz = write_off + len; if (write_off + len >= Buf.Capacity) { - int double_capacity = Buf.Capacity * 2; - Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity); + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); } Buf.resize(needed_sz); @@ -2124,14 +2150,6 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) va_end(args_copy); } -void ImGuiTextBuffer::appendf(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - appendfv(fmt, args); - va_end(args); -} - //----------------------------------------------------------------------------- // [SECTION] ImGuiListClipper // This is currently not as flexible/powerful as it should be, needs some rework (see TODO) diff --git a/imgui.h b/imgui.h index 81a6260c..2d0c6467 100644 --- a/imgui.h +++ b/imgui.h @@ -1586,6 +1586,7 @@ struct ImGuiTextBuffer void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } + IMGUI_API void append(const char* str, const char* str_end = NULL); IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); }; From 54ba8a643ed28e2bd930b64bad9024407296d227 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 20 Jan 2019 22:23:29 +0100 Subject: [PATCH 151/195] Removed trailing spaces from text files. (#2038, #2299) --- docs/CHANGELOG.txt | 84 +++++++++++++++++++++--------------------- docs/README.md | 26 ++++++------- docs/TODO.txt | 24 ++++++------ docs/issue_template.md | 10 ++--- examples/README.txt | 50 ++++++++++++------------- misc/README.txt | 4 +- misc/cpp/README.txt | 2 +- misc/fonts/README.txt | 36 +++++++++--------- misc/natvis/README.txt | 4 +- 9 files changed, 120 insertions(+), 120 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 44146071..859f782d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -12,7 +12,7 @@ COMMITS HISTORY: https://github.com/ocornut/imgui/commits/master WHEN TO UPDATE? - Keeping your copy of dear imgui updated once in a while is recommended. -- It is generally safe to sync to the latest commit in master. +- It is generally safe to sync to the latest commit in master. The library is fairly stable and regressions tends to be fixed fast when reported. HOW TO UPDATE? @@ -23,8 +23,8 @@ HOW TO UPDATE? - If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it. - If you are dropping this repository in your codebase, please leave the demo and text files in there, they will be useful. - You may diff your previous Changelog with the one you just copied and read that diff. -- You may enable `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in imconfig.h to forcefully disable legacy names and symbols. - Doing it every once in a while is a good way to make sure you are not using obsolete symbols. Dear ImGui is in active development, +- You may enable `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in imconfig.h to forcefully disable legacy names and symbols. + Doing it every once in a while is a good way to make sure you are not using obsolete symbols. Dear ImGui is in active development, 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! @@ -40,7 +40,7 @@ Other Changes: - ImGuiTextBuffer: Added append() function (unformatted). - ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093) - ImFontAtlas: FreeType: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] -- Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created +- Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). - Examples: Win32: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. (#2264) @@ -75,15 +75,15 @@ Other Changes: the parent window of the popup instead of the newly clicked window. - Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed. - Window: Contents size is preserved while a window contents is hidden (unless it is hidden for resizing purpose). -- Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that +- Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-ends do. - Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. This is ignored by window with no title bars (often popups). This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899) - Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected - in the parent window, so there is no mismatch between the layout in parent and the position of the child window. + in the parent window, so there is no mismatch between the layout in parent and the position of the child window. - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) - DragFloat: Fixed broken mouse direction change with power!=1.0. (#2174, #2206) [@Joshhua5] -- Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary +- Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary keep the focus on the parent window, which could steal it from newly appearing windows. (#787) - Nav: Fixed animated window titles from being updated when displayed in the CTRL+Tab list. (#787) - Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function closer @@ -119,7 +119,7 @@ Other Changes: - Fixed a text rendering/clipping bug introduced in 1.66 (on 2018-10-12, commit ede3a3b9) that affect single ImDrawList::AddText() calls with single strings larger than 10k. Text/TextUnformatted() calls were not affected, but e.g. InputText() was. [@pdoane] - When the focused window become inactive don't restore focus to a window with the ImGuiWindowFlags_NoInputs flag. (#2213) [@zzzyap] -- Separator: Fixed Separator() outputting an extraneous empty line when captured into clipboard/text/file. +- Separator: Fixed Separator() outputting an extraneous empty line when captured into clipboard/text/file. - Demo: Added ShowAboutWindow() call, previously was only accessible from the demo window. - Demo: ShowAboutWindow() now display various Build/Config Information (compiler, os, etc.) that can easily be copied into bug reports. - Fixed build issue with osxcross and macOS. (#2218) [@dos1] @@ -138,7 +138,7 @@ Breaking Changes: Other Changes: -- Fixed calling SetNextWindowSize()/SetWindowSize() with non-integer values leading to +- Fixed calling SetNextWindowSize()/SetWindowSize() with non-integer values leading to accidental alteration of window position. We now round the provided size. (#2067) - Fixed calling DestroyContext() always saving .ini data with the current context instead of the supplied context pointer. (#2066) @@ -147,7 +147,7 @@ Other Changes: - Nav: Fixed an assert in certain circumstance (mostly when using popups) when mouse positions stop being valid. (#2168) - Nav: Fixed explicit directional input not re-highlighting current nav item if there is a single item in the window and highlight has been previously disabled by the mouse. (#787) -- DragFloat: Fixed a situation where dragging with value rounding enabled or with a power curve +- DragFloat: Fixed a situation where dragging with value rounding enabled or with a power curve erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075). - DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024) - DragFloat: Disabled setting a default drag speed when one edge is FLT_MAX. (#2024) @@ -166,9 +166,9 @@ Other Changes: to the provided string to uniquely identify the child window. This was undoing an intentional change introduced in 1.50 and broken in 1.60. (#1698, #894, #713). - TextUnformatted(): Fixed a case where large-text path would read bytes past the text_end marker depending - on the position of new lines in the buffer (it wasn't affecting the output but still not the right thing to do!) -- ListBox(): Fixed frame sizing when items_count==1 unnecessarily showing a scrollbar. (#2173) [@luk1337, @ocornut] -- ListBox(): Tweaked frame sizing so list boxes will look more consistent when FramePadding is far from ItemSpacing. + on the position of new lines in the buffer (it wasn't affecting the output but still not the right thing to do!) +- ListBox(): Fixed frame sizing when items_count==1 unnecessarily showing a scrollbar. (#2173) [@luk1337, @ocornut] +- ListBox(): Tweaked frame sizing so list boxes will look more consistent when FramePadding is far from ItemSpacing. - RenderText(): Some optimization for very large text buffers, useful for non-optimized builds. - BeginMenu(): Fixed menu popup horizontal offset being off the item in the menu bar when WindowPadding=0.0f. - ArrowButton(): Fixed arrow shape being horizontally misaligned by (FramePadding.y-FramePadding.x) if they are different. @@ -226,7 +226,7 @@ Changes: isolate your patches. You can peak at imgui_widgets.cpp from 1.64 to get a sense of what is included in it, then separate your changes into several patches that can more easily be applied to 1.64 on a per-file basis. What I found worked nicely for me, was to open the diff of the old patches in an interactive merge/diff tool, - search for the corresponding function in the new code and apply the chunks manually. + search for the corresponding function in the new code and apply the chunks manually. - As a reminder, if you have any change to imgui.cpp it is a good habit to discuss them on the github, so a solution applicable on the Master branch can be found. If your company has changes that you cannot disclose you may also contact me privately. @@ -242,10 +242,10 @@ Breaking Changes: - Changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecision over time. - Removed per-window ImGuiWindowFlags_ResizeFromAnySide Beta flag in favor `io.ConfigResizeWindowsFromEdges=true` to enable the feature globally. (#1495) The feature is not currently enabled by default because it is not satisfying enough, but will eventually be. -- InputText: Renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. - Kept redirection types (will obsolete). +- InputText: Renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. + Kept redirection types (will obsolete). - InputText: Removed ImGuiTextEditCallbackData::ReadOnly since it is a duplication of (ImGuiTextEditCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). -- Renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. +- Renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). - Renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to io.ConfigMacOSXBehaviors for consistency. (#1427, #473) - Removed obsolete redirection functions: CollapsingHeader() variation with 2 bools - marked obsolete in v1.49, May 2016. @@ -259,17 +259,17 @@ Other Changes: While it was previously possible, you won't be able to CTRL-TAB out and immediately back in a window with the ImGuiWindow_NoNavFocus flag. - Window: Allow menu and popups windows from ignoring the style.WindowMinSize values so short menus/popups are not padded. (#1909) - Window: Added global io.ConfigResizeWindowsFromEdges option to enable resizing windows from their edges and from the lower-left corner. (#1495) -- Window: Collapse button shows hovering highlight + clicking and dragging on it allows to drag the window as well. +- Window: Collapse button shows hovering highlight + clicking and dragging on it allows to drag the window as well. - Added IsItemEdited() to query if the last item modified its value (or was pressed). This is equivalent to the bool returned by most widgets. It is useful in some situation e.g. using InputText() with ImGuiInputTextFlags_EnterReturnsTrue. (#2034) - InputText: Added support for buffer size/capacity changes via the ImGuiInputTextFlags_CallbackResize flag. (#2006, #1443, #1008). - InputText: Fixed not tracking the cursor horizontally when modifying the text buffer through a callback. - InputText: Fixed minor off-by-one issue when submitting a buffer size smaller than the initial zero-terminated buffer contents. -- InputText: Fixed a few pathological crash cases on single-line InputText widget with multiple millions characters worth of contents. +- InputText: Fixed a few pathological crash cases on single-line InputText widget with multiple millions characters worth of contents. Because the current text drawing function reserve for a worst-case amount of vertices and how we handle horizontal clipping, - we currently just avoid displaying those single-line widgets when they are over a threshold of 2 millions characters, + we currently just avoid displaying those single-line widgets when they are over a threshold of 2 millions characters, until a better solution is found. -- Drag and Drop: Fixed an incorrect assert when dropping a source that is submitted after the target (bug introduced with 1.62 changes +- Drag and Drop: Fixed an incorrect assert when dropping a source that is submitted after the target (bug introduced with 1.62 changes related to the addition of IsItemDeactivated()). (#1875, #143) - Drag and Drop: Fixed ImGuiDragDropFlags_SourceNoDisableHover to affect hovering state prior to calling IsItemHovered() + fixed description. (#143) - Drag and Drop: Calling BeginTooltip() between a BeginDragSource()/EndDragSource() or BeginDropTarget()/EndDropTarget() uses adjusted tooltip @@ -282,11 +282,11 @@ Other Changes: - Misc: Added optional misc/stl/imgui_stl.h wrapper to use with STL types (e.g. InputText with std::string). (#2006, #1443, #1008) [*EDIT* renamed to misc/std/imgui_stdlib.h in 1.66] - Misc: Added IMGUI_VERSION_NUM for easy compile-time testing. (#2025) -- Misc: Added ImGuiMouseCursor_Hand cursor enum + corresponding software cursor. (#1913, 1914) [@aiekick, @ocornut] +- Misc: Added ImGuiMouseCursor_Hand cursor enum + corresponding software cursor. (#1913, 1914) [@aiekick, @ocornut] - Misc: Tweaked software mouse cursor offset to match the offset of the corresponding Windows 10 cursors. - Made assertion more clear when trying to call Begin() outside of the NewFrame()..EndFrame() scope. (#1987) - Fixed assertion when transitioning from an active ID to another within a group, affecting ColorPicker (broken in 1.62). (#2023, #820, #956, #1875). -- Fixed PushID() from keeping alive the new ID Stack top value (if a previously active widget shared the ID it would be erroneously kept alive). +- Fixed PushID() from keeping alive the new ID Stack top value (if a previously active widget shared the ID it would be erroneously kept alive). - Fixed horizontal mouse wheel not forwarding the request to the parent window if ImGuiWindowFlags_NoScrollWithMouse is set. (#1463, #1380, #1502) - Fixed a include build issue for Cygwin in non-POSIX (Win32) mode. (#1917, #1319, #276) - ImDrawList: Improved handling for worst-case vertices reservation policy when large amount of text (e.g. 1+ million character strings) @@ -305,15 +305,15 @@ Other Changes: - Examples: OSX: Added early raw OSX platform backend. (#1873) [@pagghiu, @itamago, @ocornut] - Examples: Added mac OSX & iOS + Metal example in example_apple_metal/. (#1929, #1873) [@warrenm] - Examples: Added mac OSX + OpenGL2 example in example_apple_opengl2/. (#1873) -- Examples: OpenGL3: Added shaders more versions of GLSL. (#1938, #1941, #1900, #1513, #1466, etc.) -- Examples: OpenGL3: Tweaked the imgui_impl_opengl3.cpp to work as-is with Emscripten + WebGL 2.0. (#1941). [@o-micron] +- Examples: OpenGL3: Added shaders more versions of GLSL. (#1938, #1941, #1900, #1513, #1466, etc.) +- Examples: OpenGL3: Tweaked the imgui_impl_opengl3.cpp to work as-is with Emscripten + WebGL 2.0. (#1941). [@o-micron] - Examples: OpenGL3: Made the example app default to GL 3.0 + GLSL 130 (instead of GL 3.2 + GLSL 150) unless on Mac. - Examples: OpenGL3: Added error output when shaders fail to compile/link. - Examples: OpenGL3: Added support for glew and glad OpenGL loaders out of the box. (#2001, #2002) [@jdumas] - Examples: OpenGL2: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications. (#1996) - Examples: DirectX10, DirectX11: Fixed unreleased resources in Init and Shutdown functions. (#1944) - Examples: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility. (#1989) [@matt77hias] -- Examples: Vulkan: Fixed handling of VkSurfaceCapabilitiesKHR::maxImageCount = 0 case. Tweaked present mode selections. +- Examples: Vulkan: Fixed handling of VkSurfaceCapabilitiesKHR::maxImageCount = 0 case. Tweaked present mode selections. - Examples: Win32, Glfw, SDL: Added support for the ImGuiMouseCursor_Hand cursor. @@ -323,8 +323,8 @@ Other Changes: Breaking Changes: -- TreeNodeEx(): The helper ImGuiTreeNodeFlags_CollapsingHeader flag now include ImGuiTreeNodeFlags_NoTreePushOnOpen. The flag was already set by CollapsingHeader(). - The only difference is if you were using TreeNodeEx() manually with ImGuiTreeNodeFlags_CollapsingHeader and without ImGuiTreeNodeFlags_NoTreePushOnOpen. +- TreeNodeEx(): The helper ImGuiTreeNodeFlags_CollapsingHeader flag now include ImGuiTreeNodeFlags_NoTreePushOnOpen. The flag was already set by CollapsingHeader(). + The only difference is if you were using TreeNodeEx() manually with ImGuiTreeNodeFlags_CollapsingHeader and without ImGuiTreeNodeFlags_NoTreePushOnOpen. In this case you can remove the ImGuiTreeNodeFlags_NoTreePushOnOpen flag from your call (ImGuiTreeNodeFlags_CollapsingHeader & ~ImGuiTreeNodeFlags_NoTreePushOnOpen). (#1864) This also apply if you were using internal's TreeNodeBehavior() with the ImGuiTreeNodeFlags_CollapsingHeader flag directly. - ImFontAtlas: Renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish new smaller variants and discourage using the full set. (#1859) @@ -341,23 +341,23 @@ Other Changes: before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl2.cpp before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp etc. - The idea is what we can now easily combine and maintain back-ends and reduce code redundancy. Individual files are smaller and more reusable. - Integration of imgui into a new/custom engine may also be easier as there is less overlap between "windowing / inputs" and "rendering" code, + Integration of imgui into a new/custom engine may also be easier as there is less overlap between "windowing / inputs" and "rendering" code, so you may study or grab one half of the code and not the other. - - This change was motivated by the fact that adding support for the upcoming multi-viewport feature requires more work from the Platform and Renderer - back-ends, and the amount of redundancy across files was becoming too difficult to maintain. If you use default back-ends, you'll benefit from an + - This change was motivated by the fact that adding support for the upcoming multi-viewport feature requires more work from the Platform and Renderer + back-ends, and the amount of redundancy across files was becoming too difficult to maintain. If you use default back-ends, you'll benefit from an easy update path to support multi-viewports later (for future ImGui 1.7x). - - This is not strictly a breaking change if you keep your old bindings, but when you'll want to fully update your bindings, - expect to have to reshuffle a few things. + - This is not strictly a breaking change if you keep your old bindings, but when you'll want to fully update your bindings, + expect to have to reshuffle a few things. - Each example still has its own main.cpp which you may refer you to understand how to initialize and glue everything together. - Some frameworks (such as the Allegro, Marmalade) handle both the "platform" and "rendering" part, and your custom engine may as well. - Read examples/README.txt for details. - Added IsItemDeactivated() to query if the last item was active previously and isn't anymore. Useful for Undo/Redo patterns. (#820, #956, #1875) -- Added IsItemDeactivatedAfterChange() [*EDIT* renamed to IsItemDeactivatedAfterEdit() in 1.63] if the last item was active previously, - is not anymore, and during its active state modified a value. Note that you may still get false positive (e.g. drag value and while +- Added IsItemDeactivatedAfterChange() [*EDIT* renamed to IsItemDeactivatedAfterEdit() in 1.63] if the last item was active previously, + is not anymore, and during its active state modified a value. Note that you may still get false positive (e.g. drag value and while holding return on the same value). (#820, #956, #1875) - Nav: Added support for PageUp/PageDown (explorer-style: first aim at bottom/top most item, when scroll a page worth of contents). (#787) - Nav: To keep the navigated item in view we also attempt to scroll the parent window as well as the current window. (#787) -- ColorEdit3, ColorEdit4, ColorButton: Added ImGuiColorEditFlags_NoDragDrop flag to disable ColorEditX as drag target and ColorButton as drag source. (#1826) +- ColorEdit3, ColorEdit4, ColorButton: Added ImGuiColorEditFlags_NoDragDrop flag to disable ColorEditX as drag target and ColorButton as drag source. (#1826) - BeginDragDropSource(): Offset tooltip position so it is off the mouse cursor, but also closer to it than regular tooltips, and not clamped by viewport. (#1739) - BeginDragDropTarget(): Added ImGuiDragDropFlags_AcceptNoPreviewTooltip flag to request hiding the drag source tooltip from the target site. (#143) - BeginCombo(), BeginMainMenuBar(), BeginChildFrame(): Temporary style modification are restored at the end of BeginXXX instead of EndXXX, to not affect tooltips and child windows. @@ -369,15 +369,15 @@ Other Changes: - ImFontAtlas: Added GetGlyphRangesChineseSimplifiedCommon() helper that returns a list of ~2500 most common Simplified Chinese characters. (#1859) [@JX-Master, @ocornut] - Examples: OSX: Added imgui_impl_osx.mm binding to be used along with e.g. imgui_impl_opengl2.cpp. (#281, #1870) [@pagghiu, @itamago, @ocornut] - Examples: GLFW: Made it possible to Shutdown/Init the backend again (by reseting the time storage properly). (#1827) [@ice1000] -- Examples: Win32: Fixed handling of mouse wheel messages to support sub-unit scrolling messages (typically sent by track-pads). (#1874) [@zx64] +- Examples: Win32: Fixed handling of mouse wheel messages to support sub-unit scrolling messages (typically sent by track-pads). (#1874) [@zx64] - Examples: SDL+Vulkan: Added SDL+Vulkan example. -- Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. Added clipboard support. +- Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. Added clipboard support. - Examples: Allegro5: Unindexing buffers ourselves as Allegro indexed drawing primitives are buggy in the DirectX9 back-end (will be fixed in Allegro 5.2.5+). - Examples: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from ImGui_ImplDX12_NewFrame() to ImGui_ImplDX12_RenderDrawData() which makes a lots more sense. (#301) -- Examples: Vulkan: Reordered parameters ImGui_ImplVulkan_RenderDrawData() to be consistent with other bindings, a good occasion since we refactored the code. +- Examples: Vulkan: Reordered parameters ImGui_ImplVulkan_RenderDrawData() to be consistent with other bindings, a good occasion since we refactored the code. - Examples: FreeGLUT: Added FreeGLUT bindings. Added FreeGLUT+OpenGL2 example. (#801) - Examples: The functions in imgui_impl_xxx.cpp are prefixed with IMGUI_IMPL_API (which defaults to IMGUI_API) to facilitate some uses. (#1888) -- Examples: Fixed bindings to use ImGuiMouseCursor_COUNT instead of old name ImGuiMouseCursor_Count_ so they can compile with IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#1887) +- Examples: Fixed bindings to use ImGuiMouseCursor_COUNT instead of old name ImGuiMouseCursor_Count_ so they can compile with IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#1887) - Misc: Updated stb_textedit from 1.09 + patches to 1.12 + minor patches. - Internals: PushItemFlag() flags are inherited by BeginChild(). @@ -473,7 +473,7 @@ Breaking Changes: - Renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. - Removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it should be easy to replicate on your side (you can find the code in 1.53). - [EDITED] Window: BeginChild() with an explicit name doesn't include the hash within the internal window name. (#1698) - This change was erroneously introduced, undoing the change done for #894, #713, and not documented properly in the original + This change was erroneously introduced, undoing the change done for #894, #713, and not documented properly in the original 1.60 release Changelog. It was fixed on 2018-09-28 (1.66) and I wrote this paragraph the same day. Other Changes: @@ -487,7 +487,7 @@ Other Changes: - See https://github.com/ocornut/imgui/issues/1599 for recommended gamepad mapping or download PNG/PSD at http://goo.gl/9LgVZW - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. Read imgui.cpp for more details. - To use Keyboard Navigation: - - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, Escape to cancel/close, Ctrl-Tab to focus windows, etc. - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set. For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. diff --git a/docs/README.md b/docs/README.md index 113dd1e4..62934c42 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,7 +18,7 @@ Dear ImGui is a bloat-free graphical user interface library for C++. It outputs Dear ImGui is designed to enable fast iterations and to empower programmers to create content creation tools and visualization / debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and lacks certain features normally found in more high-level libraries. -Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard. +Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard. See [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui), [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Gallery](https://github.com/ocornut/imgui/issues/2265) pages to get an idea of its use cases. @@ -76,7 +76,7 @@ ImGui::ColorEdit4("Color", my_color); // Plot some values const float my_values[] = { 0.2f, 0.1f, 1.0f, 0.5f, 0.9f, 2.2f }; ImGui::PlotLines("Frame Times", my_values, IM_ARRAYSIZE(my_values)); - + // Display contents in a scrolling region ImGui::TextColored(ImVec4(1,1,0,1), "Important Stuff"); ImGui::BeginChild("Scrolling"); @@ -90,13 +90,13 @@ Result: ### How it works -Check out the References section if you want to understand the core principles behind the IMGUI paradigm. An IMGUI tries to minimize superfluous state duplication, state synchronization and state retention from the user's point of view. It is less error prone (less code and less bugs) than traditional retained-mode interfaces, and lends itself to create dynamic user interfaces. +Check out the References section if you want to understand the core principles behind the IMGUI paradigm. An IMGUI tries to minimize superfluous state duplication, state synchronization and state retention from the user's point of view. It is less error prone (less code and less bugs) than traditional retained-mode interfaces, and lends itself to create dynamic user interfaces. -Dear ImGui outputs vertex buffers and command lists that you can easily render in your application. The number of draw calls and state changes required to render them is fairly small. Because Dear ImGui doesn't know or touch graphics state directly, you can call its functions anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate dear imgui with your existing codebase. +Dear ImGui outputs vertex buffers and command lists that you can easily render in your application. The number of draw calls and state changes required to render them is fairly small. Because Dear ImGui doesn't know or touch graphics state directly, you can call its functions anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate dear imgui with your existing codebase. _A common misunderstanding is to mistake immediate mode gui for immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes as the gui functions are called. This is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are decently optimal and you can render them later, in your app or even remotely._ -Dear ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue (hot code reload) feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! Dear ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, an entire game making editor/framework, etc. +Dear ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue (hot code reload) feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! Dear ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, an entire game making editor/framework, etc. Demo Binaries ------------- @@ -194,7 +194,7 @@ Demo window References ---------- -The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works. +The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works. - [Johannes 'johno' Norneby's article](http://www.johno.se/book/imgui.html). - [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf). - [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/). @@ -216,15 +216,15 @@ Frequently Asked Question (FAQ) **Where is the documentation?** -- The documentation is at the top of imgui.cpp + effectively imgui.h. -- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output. -- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder. +- The documentation is at the top of imgui.cpp + effectively imgui.h. +- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output. +- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder. - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort. -- Your programming IDE is your friend, find the type or function declaration to find comments associated to it. +- Your programming IDE is your friend, find the type or function declaration to find comments associated to it. **Which version should I get?** -I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported. +I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported. You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) branches. Even though they are marked beta, several projects are using them and they are kept in sync with master regularly. @@ -314,9 +314,9 @@ And all other supporters; THANK YOU! Credits ------- -Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com). +Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com). -I first discovered the IMGUI paradigm at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it. +I first discovered the IMGUI paradigm at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it. Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license). diff --git a/docs/TODO.txt b/docs/TODO.txt index 624e6309..a183e67c 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -25,7 +25,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: using SetWindowPos() inside Begin() and moving the window with the mouse reacts a very ugly glitch. We should just defer the SetWindowPos() call. - window: GetWindowSize() returns (0,0) when not calculated? (#1045) - 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. + - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. - 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/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero. - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse) @@ -60,7 +60,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: activate by identifier (trigger button, focus given id) - 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) - - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. + - 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) - input text: expose CursorPos in char filter event (#816) - input text: access public fields via a non-callback API e.g. InputTextGetState("xxx") that may return NULL if not active. @@ -93,19 +93,19 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding. - layout: BeginGroup() needs a border option. (~#1496) - layout: vertical alignment of mixed height items (e.g. buttons) within a same line (#1284) - + - columns: sizing policy (e.g. for each column: fixed size, %, fill, distribute default size among fills) (#513, #125) - columns: add a conditional parameter to SetColumnOffset() (#513, #125) - columns: headers. re-orderable. (#513, #125) - columns: optional sorting modifiers (up/down), sort list so sorting can be done multi-criteria. notify user when sort order changed. - - columns: option to alternate background colors on odd/even scanlines. - - columns: allow columns to recurse. - - columns: allow a same columns set to be interrupted by e.g. CollapsingHeader and resume with columns in sync when moving them. + - columns: option to alternate background colors on odd/even scanlines. + - columns: allow columns to recurse. + - columns: allow a same columns set to be interrupted by e.g. CollapsingHeader and resume with columns in sync when moving them. - columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (#125) - columns: flag to add horizontal separator above/below? - columns/layout: setup minimum line height (equivalent of automatically calling AlignFirstTextHeightToWidgets) -!- color: the color conversion helpers/types are a mess and needs sorting out. +!- color: the color conversion helpers/types are a mess and needs sorting out. - color: (api breaking) ImGui::ColorConvertXXX functions should be loose ImColorConvertXX to match imgui_internals.h - plot: full featured plot/graph api w/ scrolling, zooming etc. all bell & whistle. why not! @@ -122,7 +122,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - 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) - + - dock: merge docking branch (#2109) - dock: dock out from a collapsing header? would work nicely but need emitting window to keep submitting the code. @@ -171,8 +171,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - tooltip: drag and drop with tooltip near monitor edges lose/changes its last direction instead of locking one. The drag and drop tooltip should always follow without changing direction. - tooltip: tooltip that doesn't fit in entire screen seems to lose their "last preferred direction" and may teleport when moving mouse. - tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic. - - tooltip: tooltips with delay timers? or general timer policy? (instantaneous vs timed): IsItemHovered() with timer + implicit aabb-id for items with no ID. (#1485) - + - tooltip: tooltips with delay timers? or general timer policy? (instantaneous vs timed): IsItemHovered() with timer + implicit aabb-id for items with no ID. (#1485) + - menus: calling BeginMenu() twice with a same name doesn't append as Begin() does for regular windows (#1207) - menus: menu bars inside modal windows are acting weird. - status-bar: add a per-window status bar helper similar to what menu-bar does. @@ -180,7 +180,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - shortcuts,menus: global-style shortcut api e.g. "Save (CTRL+S)" -> explicit flag for recursing into closed menu - shortcuts: programmatically access shortcuts "Focus("&Save")) - menus: menu-bar: main menu-bar could affect clamping of windows position (~ akin to modifying DisplayMin) - - menus: hovering from menu to menu on a menu-bar has 1 frame without any menu, which is a little annoying. ideally either 0 either longer. + - menus: hovering from menu to menu on a menu-bar has 1 frame without any menu, which is a little annoying. ideally either 0 either longer. - text: selectable text (for copy) as a generic feature (ItemFlags?) - text: proper alignment options in imgui_internal.h @@ -240,7 +240,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i !- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions). - font: a CalcTextHeight() helper could run faster than CalcTextSize().y - font: enforce monospace through ImFontConfig (for icons?) + create dual ImFont output from same input, reusing rasterized data but with different glyphs/AdvanceX - - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data + - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data - font: PushFontSize API (#1018) - font: MemoryTTF taking ownership confusing/not obvious, maybe default should be opposite? - font/demo: add tools to show glyphs used by a text blob, display U16 value, list missing glyphs. diff --git a/docs/issue_template.md b/docs/issue_template.md index 2ce90bee..73330b22 100644 --- a/docs/issue_template.md +++ b/docs/issue_template.md @@ -8,7 +8,7 @@ https://discourse.dearimgui.org/c/getting-started 3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1). -4. Delete points 1-4 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue. +4. Delete points 1-4 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue. ---- @@ -19,17 +19,17 @@ _(you may also go to Demo>About Window, and click "Config/Build Information" to Version: XXX Branch: XXX _(master/viewport/docking/etc.)_ -**Back-end/Renderer/Compiler/OS** +**Back-end/Renderer/Compiler/OS** Back-ends: imgui_impl_XXX.cpp + imgui_impl_XXX.cpp _(or specify if using a custom engine/back-end)_ Compiler: XXX _(if the question is related to building or platform specific features)_ -Operating System: XXX +Operating System: XXX -**My Issue/Question:** +**My Issue/Question:** XXX _(please provide as much context as possible)_ -**Screenshots/Video** +**Screenshots/Video** XXX _(you can drag files here)_ diff --git a/examples/README.txt b/examples/README.txt index 3039f821..017af6ee 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -25,7 +25,7 @@ This folder contains two things: - Example applications (standalone, ready-to-build) using the aforementioned bindings. They are the in the XXXX_example/ sub-folders. -You can find binaries of some of those example applications at: +You can find binaries of some of those example applications at: http://www.miracleworld.net/imgui/binaries @@ -35,7 +35,7 @@ You can find binaries of some of those example applications at: - Please read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. Please read the comments and instruction at the top of each file. - + - If you are using of the backend provided here, so you can copy the imgui_impl_xxx.cpp/h files to your project and use them unmodified. Each imgui_impl_xxxx.cpp comes with its own individual ChangeLog at the top of the .cpp files, so if you want to update them later it will be easier to @@ -43,13 +43,13 @@ You can find binaries of some of those example applications at: - Dear ImGui has 0 to 1 frame of lag for most behaviors, at 60 FPS your experience should be pleasant. However, consider that OS mouse cursors are typically drawn through a specific hardware accelerated path - and will feel smoother than common GPU rendered contents (including Dear ImGui windows). - You may experiment with the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor itself, + and will feel smoother than common GPU rendered contents (including Dear ImGui windows). + You may experiment with the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor itself, to visualize the lag between a hardware cursor and a software cursor. However, rendering a mouse cursor at 60 FPS will feel slow. It might be beneficial to the user experience to switch to a software rendered - cursor only when an interactive drag is in progress. + cursor only when an interactive drag is in progress. Note that some setup or GPU drivers are likely to be causing extra lag depending on their settings. - If you feel that dragging windows feels laggy and you are not sure who to blame: try to build an + If you feel that dragging windows feels laggy and you are not sure who to blame: try to build an application drawing a shape directly under the mouse cursor. @@ -71,17 +71,17 @@ Most the example bindings are split in 2 parts: - Some bindings for higher level frameworks carry both "Platform" and "Renderer" parts in one file. This is the case for Allegro 5 (imgui_impl_allegro5.cpp), Marmalade (imgui_impl_marmalade5.cpp). - - If you use your own engine, you may decide to use some of existing bindings and/or rewrite some using + - If you use your own engine, you may decide to use some of existing bindings and/or rewrite some using your own API. As a recommendation, if you are new to Dear ImGui, try using the existing binding as-is - first, before moving on to rewrite some of the code. Although it is tempting to rewrite both of the + first, before moving on to rewrite some of the code. Although it is tempting to rewrite both of the imgui_impl_xxxx files to fit under your coding style, consider that it is not necessary! In fact, if you are new to Dear ImGui, rewriting them will almost always be harder. - Example: your engine is built over Windows + DirectX11 but you have your own high-level rendering + Example: your engine is built over Windows + DirectX11 but you have your own high-level rendering system layered over DirectX11. - Suggestion: step 1: try using imgui_impl_win32.cpp + imgui_impl_dx11.cpp first. - Once this work, _if_ you want you can replace the imgui_impl_dx11.cpp code with a custom renderer - using your own functions, etc. + Suggestion: step 1: try using imgui_impl_win32.cpp + imgui_impl_dx11.cpp first. + Once this work, _if_ you want you can replace the imgui_impl_dx11.cpp code with a custom renderer + using your own functions, etc. Please consider using the bindings to the lower-level platform/graphics API as-is. Example: your engine is multi-platform (consoles, phones, etc.), you have high-level systems everywhere. @@ -89,10 +89,10 @@ Most the example bindings are split in 2 parts: This is counter-intuitive, but this will get you running faster! Once you better understand how imgui works and is bound, you can rewrite the code using your own systems. - - Road-map: Dear ImGui 1.70 (WIP currently in the "viewport" branch) will allows imgui windows to be - seamlessly detached from the main application window. This is achieved using an extra layer to the + - Road-map: Dear ImGui 1.70 (WIP currently in the "viewport" branch) will allows imgui windows to be + seamlessly detached from the main application window. This is achieved using an extra layer to the platform and renderer bindings, which allows imgui to communicate platform-specific requests. - If you decide to use unmodified imgui_impl_xxxx.cpp files, you will automatically benefit from + If you decide to use unmodified imgui_impl_xxxx.cpp files, you will automatically benefit from improvements and fixes related to viewports and platform windows without extra work on your side. @@ -125,7 +125,7 @@ Third-party framework, graphics API and languages bindings are listed at: https://github.com/ocornut/imgui/wiki/Bindings Languages: C, C#, ChaiScript, D, Go, Haxe, Java, Lua, Odin, Pascal, PureBasic, Python, Rust, Swift... - Frameworks: Cinder, Cocoa (OSX), Cocos2d-x, Emscripten, SFML, GML/GameMaker Studio, Irrlicht, Ogre, + Frameworks: Cinder, Cocoa (OSX), Cocos2d-x, Emscripten, SFML, GML/GameMaker Studio, Irrlicht, Ogre, OpenSceneGraph, openFrameworks, LOVE, NanoRT, Nim Game Lib, Qt3d, SFML, Unreal Engine 4... Miscellaneous: Software Renderer, RemoteImgui, etc. @@ -135,12 +135,12 @@ Third-party framework, graphics API and languages bindings are listed at: --------------------------------------- Building: - Unfortunately in 2018 it is still tedious to create and maintain portable build files using external - libraries (the kind we're using here to create a window and render 3D triangles) without relying on + Unfortunately in 2018 it is still tedious to create and maintain portable build files using external + libraries (the kind we're using here to create a window and render 3D triangles) without relying on third party software. For most examples here I choose to provide: - Makefiles for Linux/OSX - Batch files for Visual Studio 2008+ - - A .sln project file for Visual Studio 2010+ + - A .sln project file for Visual Studio 2010+ - Xcode project files for the Apple examples Please let me know if they don't work with your setup! You can probably just import the imgui_impl_xxx.cpp/.h files into your own codebase or compile those @@ -150,7 +150,7 @@ Building: example_win32_directx9/ DirectX9 example, Windows only. = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx9.cpp - + example_win32_directx10/ DirectX10 example, Windows only. = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx10.cpp @@ -158,7 +158,7 @@ example_win32_directx10/ example_win32_directx11/ DirectX11 example, Windows only. = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx11.cpp - + example_win32_directx12/ DirectX12 example, Windows only. = main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp @@ -188,9 +188,9 @@ example_glfw_opengl2/ example_glfw_opengl3/ GLFW (Win32, Mac, Linux) + OpenGL3+/ES2/ES3 example (programmable pipeline). = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp - This uses more modern OpenGL calls and custom shaders. + This uses more modern OpenGL calls and custom shaders. Prefer using that if you are using modern OpenGL in your application (anything with shaders). - + example_glfw_vulkan/ GLFW (Win32, Mac, Linux) + Vulkan example. = main.cpp + imgui_impl_glfw.cpp + imgui_impl_vulkan.cpp @@ -204,12 +204,12 @@ example_sdl_opengl2/ This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter. If your code is using GL3+ context or any semi modern OpenGL calls, using this renderer is likely to make things more complicated, will require your code to reset many OpenGL attributes to their initial - state, and might confuse your GPU driver. One star, not recommended. + state, and might confuse your GPU driver. One star, not recommended. example_sdl_opengl3/ SDL2 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example. = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl3.cpp - This uses more modern OpenGL calls and custom shaders. + This uses more modern OpenGL calls and custom shaders. Prefer using that if you are using modern OpenGL in your application (anything with shaders). example_sdl_vulkan/ diff --git a/misc/README.txt b/misc/README.txt index ff23d7fc..be3af5ae 100644 --- a/misc/README.txt +++ b/misc/README.txt @@ -13,6 +13,6 @@ misc/freetype/ Benefit from better FreeType rasterization, in particular for small fonts. misc/natvis/ - Natvis file to describe dear imgui types in the Visual Studio debugger. - With this, types like ImVector<> will be displayed nicely in the debugger. + Natvis file to describe dear imgui types in the Visual Studio debugger. + With this, types like ImVector<> will be displayed nicely in the debugger. You can include this file a Visual Studio project file, or install it in Visual Studio folder. diff --git a/misc/cpp/README.txt b/misc/cpp/README.txt index dedfa747..9067cac0 100644 --- a/misc/cpp/README.txt +++ b/misc/cpp/README.txt @@ -3,7 +3,7 @@ imgui_stdlib.h + imgui_stdlib.cpp InputText() wrappers for C++ standard library (STL) type: std::string. This is also an example of how you may wrap your own similar types. -imgui_scoped.h +imgui_scoped.h [Experimental, not currently in main repository] Additional header file with some RAII-style wrappers for common ImGui functions. Try by merging: https://github.com/ocornut/imgui/pull/2197 diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt index 004dca3d..fd4ed1bf 100644 --- a/misc/fonts/README.txt +++ b/misc/fonts/README.txt @@ -3,7 +3,7 @@ The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' (by Tristan Grimmer), a 13 pixels high, pixel-perfect font used by default. We embed it font in source code so you can use Dear ImGui without any file system access. -You may also load external .TTF/.OTF files. +You may also load external .TTF/.OTF files. The files in this folder are suggested fonts, provided as a convenience. (Note: .OTF support in imstb_truetype.h currently doesn't appear to load every font) @@ -45,9 +45,9 @@ If you have other loading/merging/adding fonts, you can post on the Dear ImGui " USING ICONS --------------------------------------- -Using an icon font (such as FontAwesome: http://fontawesome.io or OpenFontIcons. https://github.com/traverseda/OpenFontIcons) +Using an icon font (such as FontAwesome: http://fontawesome.io or OpenFontIcons. https://github.com/traverseda/OpenFontIcons) is an easy and practical way to use icons in your Dear ImGui application. -A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without +A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without having to change fonts back and forth. To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut: @@ -77,8 +77,8 @@ Example Usage: ImGui::Text("%s among %d items", ICON_FA_SEARCH, count); ImGui::Button(ICON_FA_SEARCH " Search"); // C string _literals_ can be concatenated at compilation time, e.g. "hello" " world" - // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" - + // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" + See Links below for other icons fonts and related tools. @@ -96,7 +96,7 @@ Load .TTF/.OTF file with: ImGuiIO& io = ImGui::GetIO(); ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); - + // Select font at runtime ImGui::Text("Hello"); // use the default font (which is the first loaded font) ImGui::PushFont(font2); @@ -113,13 +113,13 @@ For advanced options create a ImFontConfig structure and pass it to the AddFont If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. The typical result of failing to upload a texture is if every glyphs appears as white rectangles. -In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you +In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you set OversampleH/OversampleV to 1 and use a small font size. Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. Some solutions: - - 1) Reduce glyphs ranges by calculating them from source localization data. + - 1) Reduce glyphs ranges by calculating them from source localization data. You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win! - 2) You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size. - 3) Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). @@ -144,14 +144,14 @@ Add a fourth parameter to bake specific font ranges only: // Basic Latin, Extended Latin io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); - + // Default + Selection of 2500 Ideographs used by Simplified Chinese io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - + // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); -See "BUILDING CUSTOM GLYPH RANGES" section to create your own ranges. +See "BUILDING CUSTOM GLYPH RANGES" section to create your own ranges. Offset font vertically by altering the io.Font->DisplayOffset value: ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); @@ -163,8 +163,8 @@ Offset font vertically by altering the io.Font->DisplayOffset value: --------------------------------------- Dear ImGui uses imstb_truetype.h to rasterize fonts (with optional oversampling). -This technique and its implementation are not ideal for fonts rendered at _small sizes_, which may appear a -little blurry or hard to read. +This technique and its implementation are not ideal for fonts rendered at _small sizes_, which may appear a +little blurry or hard to read. There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder. @@ -178,7 +178,7 @@ Also note that correct sRGB space blending will have an important effect on your --------------------------------------- You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input. -For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. +For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. ImVector ranges; ImFontGlyphRangesBuilder builder; @@ -198,11 +198,11 @@ For example: for a game where your script is known, if you can feed your entire Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array that you can embed in source code. See the documentation in binary_to_compressed_c.cpp for instruction on how to use the tool. You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see README). -The tool optionally used Base85 encoding to reduce the size of _source code_ but the read-only arrays will be about 20% bigger. +The tool optionally used Base85 encoding to reduce the size of _source code_ but the read-only arrays will be about 20% bigger. Then load the font with: ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); -or: +or: ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); @@ -221,7 +221,7 @@ Cousine-Regular.ttf by Steve Matteson Digitized data copyright (c) 2010 Google Corporation. Licensed under the SIL Open Font License, Version 1.1 - https://fonts.google.com/specimen/Cousine + https://fonts.google.com/specimen/Cousine DroidSans.ttf @@ -267,7 +267,7 @@ ICON FONTS Kenney Icon Font (Game Controller Icons) https://github.com/nicodinh/kenney-icon-font - + IcoMoon - Custom Icon font builder https://icomoon.io/app diff --git a/misc/natvis/README.txt b/misc/natvis/README.txt index 60073874..1219db45 100644 --- a/misc/natvis/README.txt +++ b/misc/natvis/README.txt @@ -1,4 +1,4 @@ -Natvis file to describe dear imgui types in the Visual Studio debugger. -With this, types like ImVector<> will be displayed nicely in the debugger. +Natvis file to describe dear imgui types in the Visual Studio debugger. +With this, types like ImVector<> will be displayed nicely in the debugger. You can include this file a Visual Studio project file, or install it in Visual Studio folder. From ea7206fd4fce6ac5690a48584a52cf67ead154e7 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 21 Jan 2019 13:58:29 +0100 Subject: [PATCH 152/195] Fixed using imgui_freetype.cpp in unity builds. (#2302) --- docs/CHANGELOG.txt | 1 + misc/freetype/imgui_freetype.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 859f782d..b2b71e44 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -40,6 +40,7 @@ Other Changes: - ImGuiTextBuffer: Added append() function (unformatted). - ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093) - ImFontAtlas: FreeType: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] +- ImFontAtlas: FreeType: Fixed using imgui_freetype.cpp in unity builds. (#2302) - Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index a4a18119..1b3843b3 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -244,10 +244,12 @@ namespace } } +#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) #define STBRP_ASSERT(x) IM_ASSERT(x) #define STBRP_STATIC #define STB_RECT_PACK_IMPLEMENTATION #include "imstb_rectpack.h" +#endif struct ImFontBuildSrcGlyphFT { From 2d21a64fed99f8262f4cb6bb76e7bfad19d2b545 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 21 Jan 2019 14:25:13 +0100 Subject: [PATCH 153/195] Comments --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 998b2d15..de9456e8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5263,10 +5263,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) window->Pos = FindBestWindowPosForPopup(window); + // Late create viewport if we don't fit within our current host viewport. if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned && !window->Viewport->PlatformWindowMinimized) if (!window->Viewport->GetRect().Contains(window->Rect())) { - // Late create viewport, based on the assumption that with our calculations, the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport) + // This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport) //ImGuiViewport* old_viewport = window->Viewport; window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoFocusOnAppearing); @@ -7413,7 +7414,7 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view /* if (viewport->LastFrameActive < g.FrameCount && viewport->Window != current_window && viewport->Window != NULL && current_window != NULL) { - //IMGUI_DEBUG_LOG("[%05d] Window '%s' steal Viewport %08X from Window '%s'\n", g.FrameCount, current_window->Name, viewport->ID, viewport->Window->Name); + //IMGUI_DEBUG_LOG("Window '%s' steal Viewport %08X from Window '%s'\n", g.FrameCount, current_window->Name, viewport->ID, viewport->Window->Name); viewport->Window = current_window; viewport->ID = current_window->ID; } @@ -7423,6 +7424,7 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view if (g.CurrentViewport == viewport) return; g.CurrentViewport = viewport; + //IMGUI_DEBUG_LOG("SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0); // Notify platform layer of viewport changes // FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI From 1e4cf67a530d8f1b178ff45b8b92848890a93349 Mon Sep 17 00:00:00 2001 From: Thomas Ruf Date: Mon, 21 Jan 2019 16:43:07 +0100 Subject: [PATCH 154/195] avoid floating point exception when _EM_OVERFLOW is enabled (#2303) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index d00f46dc..81cf443d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3729,7 +3729,7 @@ void ImGui::EndFrame() IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?"); // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) - if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f) + if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) { g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y); g.PlatformImeLastPos = g.PlatformImePos; From f994b8aab8814803bb7486585acaabf1b2cc56c0 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 21 Jan 2019 15:13:54 +0100 Subject: [PATCH 155/195] ImHash: Moved crc32 table out of the function so it can be shared, also avoid cases were compiler tries to makes its initialization thread-safe. --- imgui.cpp | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 81cf443d..c3a70328 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1433,28 +1433,39 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) } #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +// CRC32 needs a 1KB lookup table (not cache friendly) +// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: +// - avoid an unnecessary branch/memory tap, - keep the ImHash() function usable by static constructors, - make it thread-safe. +static const ImU32 GCrc32LookupTable[256] = +{ + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, +}; + // Pass data_size == 0 for zero-terminated strings, data_size > 0 for non-string data. // Pay attention that data_size==0 will yield different results than passing strlen(data) because the zero-terminated codepath handles ###. // This should technically be split into two distinct functions (ImHashData/ImHashStr), perhaps once we remove the silly static variable. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. ImU32 ImHash(const void* data, int data_size, ImU32 seed) { - static ImU32 crc32_lut[256] = { 0 }; - if (!crc32_lut[1]) - { - const ImU32 polynomial = 0xEDB88320; - for (ImU32 i = 0; i < 256; i++) - { - ImU32 crc = i; - for (ImU32 j = 0; j < 8; j++) - crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial); - crc32_lut[i] = crc; - } - } - seed = ~seed; ImU32 crc = seed; const unsigned char* current = (const unsigned char*)data; + const ImU32* crc32_lut = GCrc32LookupTable; if (data_size > 0) { @@ -2536,6 +2547,7 @@ ImGuiWindow::~ImGuiWindow() ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) { + // FIXME: ImHash with str_end doesn't behave same as with identical zero-terminated string, because of ### handling. ImGuiID seed = IDStack.back(); ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed); ImGui::KeepAliveID(id); From 28901dd10417edf76454c73200ba1b50a4504d2d Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 21 Jan 2019 15:39:43 +0100 Subject: [PATCH 156/195] Internals: Tweaks. Comments about PushID/GetID public function. --- imgui.cpp | 27 +++++++++++++++------------ imgui.h | 9 +++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c3a70328..40d90bde 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6380,71 +6380,74 @@ void ImGui::SetItemDefaultFocus() void ImGui::SetStateStorage(ImGuiStorage* tree) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GImGui->CurrentWindow; window->DC.StateStorage = tree ? tree : &window->StateStorage; } ImGuiStorage* ImGui::GetStateStorage() { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; return window->DC.StateStorage; } void ImGui::PushID(const char* str_id) { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; window->IDStack.push_back(window->GetIDNoKeepAlive(str_id)); } void ImGui::PushID(const char* str_id_begin, const char* str_id_end) { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end)); } void ImGui::PushID(const void* ptr_id) { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); } void ImGui::PushID(int int_id) { const void* ptr_id = (void*)(intptr_t)int_id; - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); } void ImGui::PopID() { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; window->IDStack.pop_back(); } ImGuiID ImGui::GetID(const char* str_id) { - return GImGui->CurrentWindow->GetID(str_id); + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id); } ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) { - return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end); + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id_begin, str_id_end); } ImGuiID ImGui::GetID(const void* ptr_id) { - return GImGui->CurrentWindow->GetID(ptr_id); + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(ptr_id); } bool ImGui::IsRectVisible(const ImVec2& size) { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow;; return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow;; return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); } diff --git a/imgui.h b/imgui.h index 2d0c6467..609823fa 100644 --- a/imgui.h +++ b/imgui.h @@ -350,13 +350,14 @@ namespace ImGui // ID stack/scopes // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - The resulting ID are hashes of the entire stack. // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, // whereas "str_id" denote a string that is only used as an ID and not normally displayed. - IMGUI_API void PushID(const char* str_id); // push string identifier into the ID stack. IDs == hash of the entire stack! - IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); - IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack. - IMGUI_API void PushID(int int_id); // push integer into the ID stack. + IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). IMGUI_API void PopID(); // pop from the ID stack. IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); From f14f93ef6e8b010588f063f9bfb1ac16b92d4d40 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 21 Jan 2019 16:05:41 +0100 Subject: [PATCH 157/195] Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 78 ++++++++++++++++++++++++++-------------------- imgui_internal.h | 6 +++- imgui_widgets.cpp | 2 +- 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b2b71e44..6377062b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,7 @@ HOW TO UPDATE? Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] +- Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - ImGuiTextBuffer: Added append() function (unformatted). diff --git a/imgui.cpp b/imgui.cpp index 40d90bde..15a9ea9b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -702,8 +702,8 @@ CODE you to animate labels. For example you may want to include varying information in a window title bar, but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: - Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "ID") - Button("World###ID"); // Label = "World", ID = hash of (..., "ID") // Same as above, even though the label looks different + Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID") + Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same as above, even though the label looks different sprintf(buf, "My game (%f FPS)###MyGame", fps); Begin(buf); // Variable title, ID = hash of "MyGame" @@ -1435,7 +1435,7 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: -// - avoid an unnecessary branch/memory tap, - keep the ImHash() function usable by static constructors, - make it thread-safe. +// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. static const ImU32 GCrc32LookupTable[256] = { 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, @@ -1456,33 +1456,46 @@ static const ImU32 GCrc32LookupTable[256] = 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, }; -// Pass data_size == 0 for zero-terminated strings, data_size > 0 for non-string data. -// Pay attention that data_size==0 will yield different results than passing strlen(data) because the zero-terminated codepath handles ###. -// This should technically be split into two distinct functions (ImHashData/ImHashStr), perhaps once we remove the silly static variable. +// Known size hash +// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. -ImU32 ImHash(const void* data, int data_size, ImU32 seed) +ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) +{ + ImU32 crc = ~seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + while (data_size-- != 0) + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; + return ~crc; +} + +// Zero-terminated string hash, with support for ### to reset back to seed value +// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. +// Because this syntax is rarely used we are optimizing for the common case. +// - If we reach ### in the string we discard the hash so far and reset to the seed. +// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed) { seed = ~seed; ImU32 crc = seed; - const unsigned char* current = (const unsigned char*)data; + const unsigned char* src = (const unsigned char*)data; const ImU32* crc32_lut = GCrc32LookupTable; - - if (data_size > 0) + if (data_size != 0) { - // Known size - while (data_size--) - crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++]; + while (data_size-- != 0) + { + unsigned char c = *src++; + if (c == '#' && src[0] == '#' && src[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } } else { - // Zero-terminated string - while (unsigned char c = *current++) + while (unsigned char c = *src++) { - // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. - // Because this syntax is rarely used we are optimizing for the common case. - // - If we reach ### in the string we discard the hash so far and reset to the seed. - // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller. - if (c == '#' && current[0] == '#' && current[1] == '#') + if (c == '#' && src[0] == '#' && src[1] == '#') crc = seed; crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; } @@ -2479,7 +2492,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(&context->DrawListSharedData) { Name = ImStrdup(name); - ID = ImHash(name, 0); + ID = ImHashStr(name, 0); IDStack.push_back(ID); Flags = ImGuiWindowFlags_None; Pos = ImVec2(0.0f, 0.0f); @@ -2547,9 +2560,8 @@ ImGuiWindow::~ImGuiWindow() ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) { - // FIXME: ImHash with str_end doesn't behave same as with identical zero-terminated string, because of ### handling. ImGuiID seed = IDStack.back(); - ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); ImGui::KeepAliveID(id); return id; } @@ -2557,7 +2569,7 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) ImGuiID ImGuiWindow::GetID(const void* ptr) { ImGuiID seed = IDStack.back(); - ImGuiID id = ImHash(&ptr, sizeof(void*), seed); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); ImGui::KeepAliveID(id); return id; } @@ -2565,13 +2577,13 @@ ImGuiID ImGuiWindow::GetID(const void* ptr) ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) { ImGuiID seed = IDStack.back(); - return ImHash(str, str_end ? (int)(str_end - str) : 0, seed); + return ImHashStr(str, str_end ? (str_end - str) : 0, seed); } ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) { ImGuiID seed = IDStack.back(); - return ImHash(&ptr, sizeof(void*), seed); + return ImHashData(&ptr, sizeof(void*), seed); } // This is only used in rare/specific situations to manufacture an ID out of nowhere. @@ -2579,7 +2591,7 @@ ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) { ImGuiID seed = IDStack.back(); const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; - ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed); + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); ImGui::KeepAliveID(id); return id; } @@ -3523,7 +3535,7 @@ void ImGui::Initialize(ImGuiContext* context) // Add .ini handle for ImGuiWindow type ImGuiSettingsHandler ini_handler; ini_handler.TypeName = "Window"; - ini_handler.TypeHash = ImHash("Window", 0, 0); + ini_handler.TypeHash = ImHashStr("Window", 0); ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; @@ -4432,7 +4444,7 @@ ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) ImGuiWindow* ImGui::FindWindowByName(const char* name) { - ImGuiID id = ImHash(name, 0); + ImGuiID id = ImHashStr(name, 0); return FindWindowByID(id); } @@ -8437,7 +8449,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) else { window = NULL; - source_id = ImHash("#SourceExtern", 0); + source_id = ImHashStr("#SourceExtern", 0); source_drag_active = true; } @@ -8852,7 +8864,7 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) g.SettingsWindows.push_back(ImGuiWindowSettings()); ImGuiWindowSettings* settings = &g.SettingsWindows.back(); settings->Name = ImStrdup(name); - settings->ID = ImHash(name, 0); + settings->ID = ImHashStr(name, 0); return settings; } @@ -8878,7 +8890,7 @@ void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) { ImGuiContext& g = *GImGui; - const ImGuiID type_hash = ImHash(type_name, 0, 0); + const ImGuiID type_hash = ImHashStr(type_name, 0); for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) if (g.SettingsHandlers[handler_n].TypeHash == type_hash) return &g.SettingsHandlers[handler_n]; @@ -8982,7 +8994,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) { - ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHash(name, 0)); + ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name, 0)); if (!settings) settings = ImGui::CreateNewWindowSettings(name); return (void*)settings; diff --git a/imgui_internal.h b/imgui_internal.h index 47bb9385..cb09bf29 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -147,7 +147,8 @@ IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 // Helpers: Misc -IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings +IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed = 0); IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } @@ -155,6 +156,9 @@ static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c = static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } #define ImQsort qsort +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] +#endif // Helpers: Geometry IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dd92c452..3fd90fd5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6084,7 +6084,7 @@ static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) { if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) { - ImGuiID id = ImHash(label, 0); + ImGuiID id = ImHashStr(label, 0); KeepAliveID(id); return id; } From c81a5a6070ee3807375de8a61210ccd35b1985cc Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 22 Jan 2019 12:38:10 +0100 Subject: [PATCH 158/195] Docking: Comments and renaming locals to facilitate debugging. --- imgui.cpp | 71 +++++++++++++++++++++++++----------------------- imgui_internal.h | 4 +-- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index baa2982b..f943b7d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10462,10 +10462,10 @@ void ImGui::DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id if (window->DockNode != NULL) continue; - ImGuiDockNode* dock_node = DockContextFindNodeByID(ctx, window->DockId); - IM_ASSERT(dock_node != NULL); // This should have been called after DockContextBuildNodesFromSettings() - if (root_id == 0 || DockNodeGetRootNode(dock_node)->ID == root_id) - DockNodeAddWindow(dock_node, window, true); + ImGuiDockNode* node = DockContextFindNodeByID(ctx, window->DockId); + IM_ASSERT(node != NULL); // This should have been called after DockContextBuildNodesFromSettings() + if (root_id == 0 || DockNodeGetRootNode(node)->ID == root_id) + DockNodeAddWindow(node, window, true); } } @@ -12589,10 +12589,10 @@ void ImGui::DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_docks if (ImGuiID src_dock_id = node_remap_pairs[dock_remap_n]) { ImGuiID dst_dock_id = node_remap_pairs[dock_remap_n + 1]; - ImGuiDockNode* dock_node = DockBuilderGetNode(src_dock_id); - for (int window_n = 0; window_n < dock_node->Windows.Size; window_n++) + ImGuiDockNode* node = DockBuilderGetNode(src_dock_id); + for (int window_n = 0; window_n < node->Windows.Size; window_n++) { - ImGuiWindow* window = dock_node->Windows[window_n]; + ImGuiWindow* window = node->Windows[window_n]; if (src_windows.contains(window->ID)) continue; @@ -12644,30 +12644,30 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) } // Bind to our dock node - ImGuiDockNode* dock_node = window->DockNode; - if (dock_node != NULL) - IM_ASSERT(window->DockId == dock_node->ID); - if (window->DockId != 0 && dock_node == NULL) + ImGuiDockNode* node = window->DockNode; + if (node != NULL) + IM_ASSERT(window->DockId == node->ID); + if (window->DockId != 0 && node == NULL) { - dock_node = DockContextFindNodeByID(ctx, window->DockId); + node = DockContextFindNodeByID(ctx, window->DockId); // We should not be docking into a split node (SetWindowDock should avoid this) - if (dock_node && dock_node->IsSplitNode()) + if (node && node->IsSplitNode()) { DockContextProcessUndockWindow(ctx, window); return; } // Create node - if (dock_node == NULL) + if (node == NULL) { - dock_node = DockContextAddNode(ctx, window->DockId); + node = DockContextAddNode(ctx, window->DockId); if (auto_dock_node) - dock_node->LastFrameAlive = g.FrameCount; + node->LastFrameAlive = g.FrameCount; } - DockNodeAddWindow(dock_node, window, true); - IM_ASSERT(dock_node == window->DockNode); + DockNodeAddWindow(node, window, true); + IM_ASSERT(node == window->DockNode); // Fix an edge case with auto-resizing windows: if they are created on the same frame they are creating their dock node, // we don't want their initial zero-size to spread to the DockNode. We preserve their size. @@ -12677,7 +12677,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) } // Undock if the ImGuiDockNodeFlags_NoDockingInCentralNode got set - if (dock_node->IsCentralNode && (dock_node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode)) + if (node->IsCentralNode && (node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode)) { DockContextProcessUndockWindow(ctx, window); return; @@ -12685,10 +12685,10 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) // Undock if our dockspace node disappeared // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. - if (dock_node->LastFrameAlive < g.FrameCount) + if (node->LastFrameAlive < g.FrameCount) { // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() - ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); + ImGuiDockNode* root_node = DockNodeGetRootNode(node); if (root_node->LastFrameAlive < g.FrameCount) { DockContextProcessUndockWindow(ctx, window); @@ -12702,34 +12702,34 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) } // Undock if we are submitted earlier than the host window - if (dock_node->HostWindow && window->BeginOrderWithinContext < dock_node->HostWindow->BeginOrderWithinContext) + if (node->HostWindow && window->BeginOrderWithinContext < node->HostWindow->BeginOrderWithinContext) { DockContextProcessUndockWindow(ctx, window); return; } // FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test) - if (dock_node->HostWindow == NULL) + if (node->HostWindow == NULL) { window->DockTabIsVisible = false; return; } - IM_ASSERT(dock_node->HostWindow); - IM_ASSERT(dock_node->IsLeafNode()); + IM_ASSERT(node->HostWindow); + IM_ASSERT(node->IsLeafNode()); // Position window - SetNextWindowPos(dock_node->Pos); - SetNextWindowSize(dock_node->Size); + SetNextWindowPos(node->Pos); + SetNextWindowSize(node->Size); g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos() window->DockIsActive = true; window->DockTabIsVisible = false; - if (dock_node->Flags & ImGuiDockNodeFlags_KeepAliveOnly) + if (node->Flags & ImGuiDockNodeFlags_KeepAliveOnly) return; // When the window is selected we mark it as visible. - if (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID) + if (node->TabBar && node->TabBar->VisibleTabId == window->ID) window->DockTabIsVisible = true; // When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesForResize. @@ -12737,22 +12737,22 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) // This is analogous to regular windows being hidden from one frame. It is especially important as nested TabBars would otherwise generate flicker in the form // of one empty frame. // Note that we set HiddenFramesForResize=2 because BeginDocked() is called just before Begin() has a chance to decrement the value. Effectively it'll be a 1 frame thing. - if (!window->DockTabIsVisible && dock_node->TabBar && dock_node->TabBar->NextSelectedTabId == window->ID) + if (!window->DockTabIsVisible && node->TabBar && node->TabBar->NextSelectedTabId == window->ID) window->HiddenFramesForResize = 2; // Update window flag IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) == 0); window->Flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoResize; - if (dock_node->IsHiddenTabBar) + if (node->IsHiddenTabBar) window->Flags |= ImGuiWindowFlags_NoTitleBar; else window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed! // Save new dock order only if the tab bar is active - if (dock_node->TabBar) + if (node->TabBar) window->DockOrder = (short)DockNodeGetTabOrder(window); - if ((dock_node->WantCloseAll || dock_node->WantCloseTabID == window->ID) && p_open != NULL) + if ((node->WantCloseAll || node->WantCloseTabID == window->ID) && p_open != NULL) *p_open = false; // Update ChildId to allow returning from Child to Parent with Escape @@ -13847,13 +13847,16 @@ void ImGui::ShowDockingDebug() if (node->Windows.Size > 0) open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); else - open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: split %s (act: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); + open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %s split (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); if (open) { IM_ASSERT(node->ChildNodes[0] == NULL || node->ChildNodes[0]->ParentNode == node); IM_ASSERT(node->ChildNodes[1] == NULL || node->ChildNodes[1]->ParentNode == node); ImGui::BulletText("Pos (%.0f,%.0f), Size (%.0f, %.0f) Ref (%.0f, %.0f)", node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y); + ImGui::BulletText("VisibleWindow: 0x%08X %s", node->VisibleWindow ? node->VisibleWindow->ID : 0, node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); + ImGui::BulletText("SelectedTabID: 0x%08X", node->SelectedTabID); + ImGui::BulletText("LastFocusedNodeID: 0x%08X", node->LastFocusedNodeID); ImGui::BulletText("Flags 0x%02X%s%s%s%s", node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "", (GImGui->FrameCount - node->LastFrameAlive < 2) ? ", IsAlive" : "", (GImGui->FrameCount - node->LastFrameActive < 2) ? ", IsActive" : ""); diff --git a/imgui_internal.h b/imgui_internal.h index ace7e26d..e609ed06 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -829,13 +829,13 @@ struct ImGuiDockNode ImGuiWindowClass WindowClass; ImGuiWindow* HostWindow; - ImGuiWindow* VisibleWindow; + ImGuiWindow* VisibleWindow; // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window. ImGuiDockNode* CentralNode; // [Root node only] Pointer to central node. ImGuiDockNode* OnlyNodeWithWindows; // [Root node only] Set when there is a single visible node within the hierarchy. int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + ImGuiDockNodeFlags_KeepAliveOnly int LastFrameActive; // Last frame number the node was updated. int LastFrameFocused; // Last frame number the node was focused. - ImGuiID LastFocusedNodeID; // [Root node only] Which of our child node (any ancestor in the hierarchy) was last focused. + ImGuiID LastFocusedNodeID; // [Root node only] Which of our child docking node (any ancestor in the hierarchy) was last focused. ImGuiID SelectedTabID; // [Tab node only] Which of our tab is selected. ImGuiID WantCloseTabID; // [Tab node only] Set when closing a specific tab. bool InitFromFirstWindowPosSize :1; From ab9cd44c89c5c4e60ade0c6045128bd87291e449 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 22 Jan 2019 13:47:15 +0100 Subject: [PATCH 159/195] Examples: DirectX9: Fix Clang warning. --- examples/imgui_impl_dx9.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/imgui_impl_dx9.cpp b/examples/imgui_impl_dx9.cpp index 6dd21143..b85c5242 100644 --- a/examples/imgui_impl_dx9.cpp +++ b/examples/imgui_impl_dx9.cpp @@ -150,14 +150,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f; float T = draw_data->DisplayPos.y + 0.5f; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f; - D3DMATRIX mat_identity = { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }; + D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } }; D3DMATRIX mat_projection = - { + { { { 2.0f/(R-L), 0.0f, 0.0f, 0.0f, 0.0f, 2.0f/(T-B), 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, - (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f, - }; + (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f + } } }; g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); From 86fce79a6c23fe6cf0caaee1aa1e3ba47ace0d05 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 22 Jan 2019 17:09:14 +0100 Subject: [PATCH 160/195] Comments + clear out VisibleWinodw field (should have no effect) --- imgui.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f943b7d0..0b7dd3f5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3164,7 +3164,7 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) { // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. - // This is because we want ActiveId to be set even when the window is stuck from moving. + // This is because we want ActiveId to be set even when the window is not permitted to move. ImGuiContext& g = *GImGui; FocusWindow(window); SetActiveID(window->MoveId, window); @@ -3252,7 +3252,8 @@ void ImGui::UpdateMouseMovingWindowEndFrame() } else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL) { - FocusWindow(NULL); // Clicking on void disable focus + // Clicking on void disable focus + FocusWindow(NULL); } } @@ -5598,6 +5599,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags 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; const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; @@ -10796,6 +10798,8 @@ static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window break; } IM_ASSERT(erased); + if (node->VisibleWindow == window) + node->VisibleWindow = NULL; // Remove tab and possibly tab bar if (node->TabBar) From bfacbac7c4bdf01e1d5661271e2566010f7945b5 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 11:05:00 +0100 Subject: [PATCH 161/195] Docking: Fix a focusing issue where dock node wouldn't be moved to the front as expected. --- imgui.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 0b7dd3f5..5519019a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11156,6 +11156,15 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) host_window->DC.CursorPos = host_window->Pos; node->Pos = host_window->Pos; node->Size = host_window->Size; + + // We set ImGuiWindowFlags_NoFocusOnAppearing because we don't want the host window to take full focus (e.g. steal NavWindow) + // But we still it bring it to the front of display. There's no way to choose this precise behavior via window flags. + // One simple case to ponder if: window A has a toggle to create windows B/C/D. Dock B/C/D together, clear the toggle and enable it again. + // When reappearing B/C/D will request focus and be moved to the top of the display pile, but they are not linked to the dock host window + // during the frame they appear. The dock host window would keep its old display order, and the sorting in EndFrame would move B/C/D back + // after the dock host window, losing their top-most status. + if (node->HostWindow->Appearing) + BringWindowToDisplayFront(node->HostWindow); } else if (node->ParentNode) { From c362a96a3fa5587107a15b31141517942b00198d Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 17:31:32 +0100 Subject: [PATCH 162/195] When resizing from an edge, the border is more visible and better follow the rounded corners. Border rendering moved to RenderOuterBorders so it can be called in a different order for docking. (#1495, #822) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 78 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6377062b..bd13b790 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,6 +36,7 @@ HOW TO UPDATE? Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. +- Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - ImGuiTextBuffer: Added append() function (unformatted). diff --git a/imgui.cpp b/imgui.cpp index 15a9ea9b..e94b8fac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1033,6 +1033,8 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(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, int border_held); + } //----------------------------------------------------------------------------- @@ -4637,12 +4639,12 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co struct ImGuiResizeGripDef { - ImVec2 CornerPos; + ImVec2 CornerPosN; ImVec2 InnerDir; int AngleMin12, AngleMax12; }; -const ImGuiResizeGripDef resize_grip_def[4] = +static const ImGuiResizeGripDef resize_grip_def[4] = { { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left @@ -4654,10 +4656,10 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_ { ImRect rect = window->Rect(); if (thickness == 0.0f) rect.Max -= ImVec2(1,1); - if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); - if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); - if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); - if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); + if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top + if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right + if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom + if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left IM_ASSERT(0); return ImRect(); } @@ -4685,7 +4687,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au 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.CornerPos); + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); @@ -4707,8 +4709,8 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au { // Resize from any of the four corners // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position - ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPos); // Corner of the window corresponding to our corner grip - CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target); + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip + CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); } if (resize_grip_n == 0 || held || hovered) resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); @@ -4722,16 +4724,17 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) { g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; - if (held) *border_held = border_n; + if (held) + *border_held = border_n; } if (held) { ImVec2 border_target = window->Pos; ImVec2 border_posn; - if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top + if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right + if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom + if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); } } @@ -4772,6 +4775,41 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au window->Size = window->SizeFull; } +static void ImGui::RenderOuterBorders(ImGuiWindow* window, int border_held) +{ + ImGuiContext& g = *GImGui; + float rounding = window->WindowRounding; + float border_size = window->WindowBorderSize; + if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + if (border_held != -1) + { + struct ImGuiResizeBorderDef + { + ImVec2 InnerDir; + ImVec2 CornerPosN1, CornerPosN2; + float OuterAngle; + }; + static const ImGuiResizeBorderDef resize_border_def[4] = + { + { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top + { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right + { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom + { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left + }; + const ImGuiResizeBorderDef& def = resize_border_def[border_held]; + ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual + } + if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + { + float y = window->Pos.y + window->TitleBarHeight() - 1; + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); + } +} + void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) { window->ParentWindow = parent_window; @@ -5193,7 +5231,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) 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.CornerPos); + 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); @@ -5202,15 +5240,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Borders - if (window_border_size > 0.0f && !(flags & ImGuiWindowFlags_NoBackground)) - window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size); - if (border_held != -1) - { - ImRect border = GetResizeBorderRect(window, border_held, grip_draw_size, 0.0f); - window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size)); - } - if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize, -1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + RenderOuterBorders(window, border_held); } // Draw navigation selection/windowing rectangle border From 9f96fcff3c21c5a31bd01eb5f590465da5979f5b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 11:29:44 +0100 Subject: [PATCH 163/195] Docking: Added ImGuiDockNodeFlags_Dockspace instead of node internal IsDockspace toward allowing the DockBuilder API to create non-dockspace nodes. --- imgui.cpp | 44 ++++++++++++++++++++++---------------------- imgui_internal.h | 12 ++++++++---- imgui_widgets.cpp | 6 +++--- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5519019a..54dbccb0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10292,7 +10292,7 @@ void ImGui::DockContextNewFrameUpdateDocking(ImGuiContext* ctx) // We can have NULL pointers when we delete nodes, but because ID are recycled this should amortize nicely (and our node count will never be very high) for (int n = 0; n < dc->Nodes.Data.Size; n++) if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) - if (!node->IsDockSpace && node->IsRootNode()) + if (node->IsRootNode() && !node->IsDockSpace()) DockNodeUpdate(node); } @@ -10440,7 +10440,8 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc node->ParentNode->ChildNodes[1] = node; node->SelectedTabID = node_settings->SelectedTabID; node->SplitAxis = node_settings->SplitAxis; - node->IsDockSpace = node_settings->IsDockSpace != 0; + if (node_settings->IsDockSpace) + node->Flags |= ImGuiDockNodeFlags_Dockspace; node->IsCentralNode = node_settings->IsCentralNode != 0; node->IsHiddenTabBar = node_settings->IsHiddenTabBar != 0; @@ -10703,7 +10704,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) WantCloseTabID = 0; InitFromFirstWindowPosSize = InitFromFirstWindowViewport = false; IsVisible = true; - IsFocused = IsDockSpace = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false; + IsFocused = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false; WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarToggle = false; } @@ -10750,7 +10751,7 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b // When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage. // In particular it is important we init the viewport from the first window so we don't create two viewports and drop one. - if (node->HostWindow == NULL && !node->IsDockSpace && node->IsRootNode()) + if (node->HostWindow == NULL && !node->IsDockSpace() && node->IsRootNode()) node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = true; // Add to tab bar if requested @@ -10956,9 +10957,10 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod IM_ASSERT(node->ParentNode == NULL || node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node); - // Inherit flags + // Inherit most flags + ImGuiDockNodeFlags flags_to_inherit = ~0 & ~ImGuiDockNodeFlags_Dockspace; if (node->ParentNode) - node->Flags = node->ParentNode->Flags; + node->Flags = node->ParentNode->Flags & flags_to_inherit; // Recurse into children // There is the possibility that one of our child becoming empty will delete itself and moving its sibling contents into 'node'. @@ -11006,7 +11008,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) { // Update visibility flag - bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsCentralNode; + bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace() : node->IsCentralNode; is_visible |= (node->Windows.Size > 0); is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); @@ -11061,7 +11063,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) } // Early out for hidden root dock nodes (when all DockId references are in inactive windows, or there is only 1 floating window holding on the DockId) - if (node->Windows.Size <= 1 && node->IsRootNode() && node->IsLeafNode() && !node->IsDockSpace && !g.IO.ConfigDockingTabBarOnSingleWindows) + if (node->Windows.Size <= 1 && node->IsRootNode() && node->IsLeafNode() && !node->IsDockSpace() && !g.IO.ConfigDockingTabBarOnSingleWindows) { if (node->Windows.Size == 1) { @@ -11099,7 +11101,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; - if (node->IsDockSpace) + if (node->IsDockSpace()) { // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); @@ -11202,7 +11204,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (central_node_hole_register_hit_test_hole) { // Add a little padding to match the "resize from edges" behavior and allow grabbing the splitter easily. - IM_ASSERT(node->IsDockSpace); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode + IM_ASSERT(node->IsDockSpace()); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode ImRect central_hole(central_node->Pos, central_node->Pos + central_node->Size); central_hole.Expand(ImVec2(-WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, -WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)); if (central_node_hole && !central_hole.IsInverted()) @@ -11321,7 +11323,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w // Move ourselves to the Menu layer (so we can be accessed by tapping Alt) + undo SkipItems flag in order to draw over the title bar even if the window is collapsed bool backup_skip_item = host_window->SkipItems; - if (!node->IsDockSpace) + if (!node->IsDockSpace()) { host_window->SkipItems = false; host_window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; @@ -11411,8 +11413,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); - tab_bar_flags |= ImGuiTabBarFlags_SaveSettings; - tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeIsDockSpace : 0); + tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags, node); @@ -11512,7 +11513,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w PopID(); // Restore SkipItems flag - if (!node->IsDockSpace) + if (!node->IsDockSpace()) { host_window->DC.NavLayerCurrent = ImGuiNavLayer_Main; host_window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); @@ -11522,7 +11523,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace() && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass; @@ -12134,7 +12135,7 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos) // There is an edge case when docking into a dockspace which only has inactive nodes (because none of the windows are active) // In this case we need to fallback into any leaf mode, possibly the central node. - if (node->IsDockSpace && node->IsRootNode()) + if (node->IsDockSpace() && node->IsRootNode()) { if (node->CentralNode && node->IsLeafNode()) // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first. return node->CentralNode; @@ -12202,11 +12203,11 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again. if (node->LastFrameActive == g.FrameCount && !(dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly)) { - IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID"); - node->IsDockSpace = true; + IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->Flags |= ImGuiDockNodeFlags_Dockspace; return; } - node->IsDockSpace = true; + node->Flags |= ImGuiDockNodeFlags_Dockspace; // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible if (dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly) @@ -12480,7 +12481,6 @@ static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID ds dst_node->Size = src_node->Size; dst_node->SizeRef = src_node->SizeRef; dst_node->SplitAxis = src_node->SplitAxis; - dst_node->IsDockSpace = src_node->IsDockSpace; dst_node->IsCentralNode = src_node->IsCentralNode; out_node_remap_pairs->push_back(src_node->ID); @@ -12955,7 +12955,7 @@ static void DockSettingsHandler_DockNodeToSettings(ImGuiDockContext* dc, ImGuiDo node_settings.SelectedTabID = node->SelectedTabID; node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None; node_settings.Depth = (char)depth; - node_settings.IsDockSpace = (char)node->IsDockSpace; + node_settings.IsDockSpace = (char)node->IsDockSpace(); node_settings.IsCentralNode = (char)node->IsCentralNode; node_settings.IsHiddenTabBar = (char)node->IsHiddenTabBar; node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y); @@ -13871,7 +13871,7 @@ void ImGui::ShowDockingDebug() ImGui::BulletText("SelectedTabID: 0x%08X", node->SelectedTabID); ImGui::BulletText("LastFocusedNodeID: 0x%08X", node->LastFocusedNodeID); ImGui::BulletText("Flags 0x%02X%s%s%s%s", - node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "", + node->Flags, node->IsDockSpace() ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "", (GImGui->FrameCount - node->LastFrameAlive < 2) ? ", IsAlive" : "", (GImGui->FrameCount - node->LastFrameActive < 2) ? ", IsActive" : ""); if (node->ChildNodes[0]) NodeDockNode(node->ChildNodes[0], "Child[0]"); diff --git a/imgui_internal.h b/imgui_internal.h index e609ed06..de762b52 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -813,6 +813,11 @@ struct ImGuiTabBarSortItem float Width; }; +enum ImGuiDockNodeFlagsPrivate_ +{ + ImGuiDockNodeFlags_Dockspace = 1 << 10 +}; + // sizeof() 116~160 struct ImGuiDockNode { @@ -842,7 +847,6 @@ struct ImGuiDockNode bool InitFromFirstWindowViewport :1; bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) bool IsFocused :1; - bool IsDockSpace :1; // Root node was created by a DockSpace() call. bool IsCentralNode :1; bool IsHiddenTabBar :1; bool HasCloseButton :1; @@ -855,6 +859,7 @@ struct ImGuiDockNode ImGuiDockNode(ImGuiID id); ~ImGuiDockNode(); bool IsRootNode() const { return ParentNode == NULL; } + bool IsDockSpace() const { return (Flags & ImGuiDockNodeFlags_Dockspace) != 0; } bool IsSplitNode() const { return ChildNodes[0] != NULL; } bool IsLeafNode() const { return ChildNodes[0] == NULL; } bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; } @@ -1384,9 +1389,8 @@ struct ImGuiItemHoveredDataBackup enum ImGuiTabBarFlagsPrivate_ { ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node - ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // Part of an explicit dockspace node node - ImGuiTabBarFlags_IsFocused = 1 << 22, - ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs }; enum ImGuiTabItemFlagsPrivate_ diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fa545290..17d87f48 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5937,8 +5937,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG } else { - const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); - const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); + const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x; + const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x; window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); } return true; @@ -6497,7 +6497,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // FIXME-DOCK: In theory we shouldn't test for the ConfigDockingNodifySingleWindows flag here. // When our single window node and OnlyNodeWithWindows are working properly we may remove this check here. ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL; - const bool single_floating_window_node = node && node->IsRootNode() && !node->IsDockSpace && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; + const bool single_floating_window_node = node && node->IsRootNode() && !node->IsDockSpace() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; if (held && single_floating_window_node && IsMouseDragging(0, 0.0f)) { // Move From 0bda7f196d4050ec6d24d7a484bf05fc173d457f Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 13:03:59 +0100 Subject: [PATCH 164/195] Docking: Fixed overlapping issue with greyed out close button. --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 54dbccb0..74229821 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11561,8 +11561,8 @@ static ImRect ImGui::DockNodeCalcTabBarRect(const ImGuiDockNode* node) ImRect r = ImRect(node->Pos.x, node->Pos.y, node->Pos.x + node->Size.x, node->Pos.y + (g.FontSize + g.Style.FramePadding.y * 2.0f)); if (node->HasCollapseButton) r.Min.x += g.Style.FramePadding.x + g.FontSize; // + g.Style.ItemInnerSpacing.x; // <-- Adding ItemInnerSpacing makes the title text moves slightly when in a tab bar. Instead we adjusted RenderArrowDockMenu() - if (node->HasCloseButton) - r.Max.x -= g.Style.FramePadding.x + g.FontSize + 1.0f; + // In DockNodeUpdateTabBar() we currently display a disabled close button even if there is none. + r.Max.x -= g.Style.FramePadding.x + g.FontSize + 1.0f; return r; } From 0737433c71a5e360be49271afc6dfa9d0cce680e Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 17:31:32 +0100 Subject: [PATCH 165/195] When resizing from an edge, the border is more visible and better follow the rounded corners. Border rendering moved to RenderOuterBorders so it can be called in a different order for docking. (#1495, #822) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 77 +++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ffc6d3f7..1fd983b9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,7 @@ Other changes: Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. +- Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - ImGuiTextBuffer: Added append() function (unformatted). diff --git a/imgui.cpp b/imgui.cpp index 74229821..fd670da6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1046,6 +1046,7 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(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, int border_held); static void EndFrameDrawDimmedBackgrounds(); // Viewports @@ -4971,12 +4972,12 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co struct ImGuiResizeGripDef { - ImVec2 CornerPos; + ImVec2 CornerPosN; ImVec2 InnerDir; int AngleMin12, AngleMax12; }; -const ImGuiResizeGripDef resize_grip_def[4] = +static const ImGuiResizeGripDef resize_grip_def[4] = { { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left @@ -4988,10 +4989,10 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_ { ImRect rect = window->Rect(); if (thickness == 0.0f) rect.Max -= ImVec2(1,1); - if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); - if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); - if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); - if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); + if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top + if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right + if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom + if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left IM_ASSERT(0); return ImRect(); } @@ -5019,7 +5020,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au 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.CornerPos); + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); @@ -5041,8 +5042,8 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au { // Resize from any of the four corners // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position - ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPos); // Corner of the window corresponding to our corner grip - CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target); + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip + CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); } if (resize_grip_n == 0 || held || hovered) resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); @@ -5056,16 +5057,17 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) { g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; - if (held) *border_held = border_n; + if (held) + *border_held = border_n; } if (held) { ImVec2 border_target = window->Pos; ImVec2 border_posn; - if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } - if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } + if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top + if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right + if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom + if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); } } @@ -5113,6 +5115,41 @@ 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, int border_held) +{ + ImGuiContext& g = *GImGui; + float rounding = window->WindowRounding; + float border_size = window->WindowBorderSize; + if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + if (border_held != -1) + { + struct ImGuiResizeBorderDef + { + ImVec2 InnerDir; + ImVec2 CornerPosN1, CornerPosN2; + float OuterAngle; + }; + static const ImGuiResizeBorderDef resize_border_def[4] = + { + { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top + { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right + { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom + { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left + }; + const ImGuiResizeBorderDef& def = resize_border_def[border_held]; + ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual + } + if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) + { + float y = window->Pos.y + window->TitleBarHeight() - 1; + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); + } +} + void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) { window->ParentWindow = parent_window; @@ -5693,7 +5730,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) 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.CornerPos); + 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); @@ -5702,15 +5739,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Borders - if (window_border_size > 0.0f && !(flags & ImGuiWindowFlags_NoBackground)) - window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size); - if (border_held != -1) - { - ImRect border = GetResizeBorderRect(window, border_held, grip_draw_size, 0.0f); - window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size)); - } - if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) - window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize, -1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + RenderOuterBorders(window, border_held); } // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. From 07ff47bf1b7fb3dced2dc91ca39efedaff34e337 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 19:54:36 +0100 Subject: [PATCH 166/195] Docking: Fixed various border / padding related inconsistency with dock node vs floating windows. (#2109) --- docs/TODO.txt | 5 ++--- imgui.cpp | 31 ++++++++++++++++++++----------- imgui_internal.h | 1 + imgui_widgets.cpp | 6 +++--- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index acc334a9..b32a5a0d 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -135,8 +135,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: B~ SetNextWindowDock() calls (with conditional) -> defer everything to DockContextUpdate (repro: Documents->[X]Windows->Dock 1 elsewhere->Click Redock All - dock: B~ tidy up tab list popup buttons features (available with manual tab-bar, see ImGuiTabBarFlags_NoTabListPopupButton code, not used by docking nodes) - dock: B- SetNextWindowDockId(0) with a second Begin() in the frame will asserts - - dock: B- inconsistent clipping/border 1-pixel issue (#2) - - dock: B- fix/disable auto-resize grip on split host nodes (~#2) + - dock: B: resize grip drawn in host window typically appears under scrollbar. - dock: B- SetNextWindowFocus() doesn't seem to apply if the window is hidden this frame, need repro (#4) - dock: B- resizing a dock tree small currently has glitches (overlapping collapse and close button, etc.) - dock: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff. @@ -323,7 +322,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for. - viewport: implicit/fallback Debug window can hog a zombie viewport (harmless, noisy?) > could at least clear out the reference on a per session basis? - viewport: need to clarify how to use GetMousePos() from a user point of view. - - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. + - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. - platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set - platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it). - platform: sdl: multi-viewport + minimized window seems to break mouse wheel events (at least under Win32). diff --git a/imgui.cpp b/imgui.cpp index fd670da6..7d93d53d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1046,7 +1046,7 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(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, int border_held); +static void RenderOuterBorders(ImGuiWindow* window); static void EndFrameDrawDimmedBackgrounds(); // Viewports @@ -2567,6 +2567,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) Appearing = false; Hidden = false; HasCloseButton = false; + ResizeBorderHeld = -1; BeginCount = 0; BeginOrderWithinParent = -1; BeginOrderWithinContext = -1; @@ -5115,13 +5116,15 @@ 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, int border_held) +static void ImGui::RenderOuterBorders(ImGuiWindow* window) { ImGuiContext& g = *GImGui; float rounding = window->WindowRounding; float border_size = window->WindowBorderSize; if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + + int border_held = window->ResizeBorderHeld; if (border_held != -1) { struct ImGuiResizeBorderDef @@ -5373,9 +5376,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) flags = window->Flags; // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies) - if (window->DockIsActive) - window->WindowBorderSize = 0.0f; - else if (flags & ImGuiWindowFlags_ChildWindow) + if (flags & ImGuiWindowFlags_ChildWindow) window->WindowBorderSize = style.ChildBorderSize; else window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; @@ -5579,13 +5580,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) want_focus = true; } + // Decide if we are going to handle borders and resize grips + const bool handle_borders_and_resize_grips = (window->DockNodeAsHost || !window->DockIsActive); + // Handle manual resize: Resize Grips, Borders, Gamepad 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); - if (!window->Collapsed) + if (handle_borders_and_resize_grips && !window->Collapsed) UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]); + window->ResizeBorderHeld = (signed char)border_held; // Synchronize window --> viewport if (window->ViewportOwned) @@ -5698,7 +5703,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { 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, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + 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); } @@ -5725,7 +5730,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) Scrollbar(ImGuiLayoutType_Vertical); // Render resize grips (after their input handling so we don't have a frame of latency) - if (!(flags & ImGuiWindowFlags_NoResize)) + if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) { for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) { @@ -5738,8 +5743,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } } - // Borders - RenderOuterBorders(window, border_held); + // Borders (for dock node host they will be rendered over after the tab bar) + if (handle_borders_and_resize_grips && !window->DockNodeAsHost) + RenderOuterBorders(window); } // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. @@ -11300,6 +11306,10 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (beginned_into_host_window) End(); } + + // Render outer borders last (after the tab bar) + if (node->IsRootNode() && host_window) + RenderOuterBorders(host_window); } // Compare TabItem nodes given the last known DockOrder (will persist in .ini file as hint), used to sort tabs when multiple tabs are added on the same frame. @@ -11403,7 +11413,6 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w ImRect title_bar_rect = ImRect(node->Pos, node->Pos + ImVec2(node->Size.x, g.FontSize + style.FramePadding.y * 2.0f)); ImU32 title_bar_col = GetColorU32(host_window->Collapsed ? ImGuiCol_TitleBgCollapsed : is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); host_window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window->WindowRounding, ImDrawCornerFlags_Top); - host_window->DrawList->AddLine(title_bar_rect.GetBL(), title_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.WindowBorderSize); // Collapse button if (CollapseButton(host_window->GetID("#COLLAPSE"), title_bar_rect.Min, node)) diff --git a/imgui_internal.h b/imgui_internal.h index de762b52..a90ff53f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1285,6 +1285,7 @@ struct IMGUI_API ImGuiWindow bool Appearing; // Set during the frame where the window is appearing (or re-appearing) bool Hidden; // Do not display (== (HiddenFramesForResize > 0) || bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 17d87f48..b547f82f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5551,7 +5551,7 @@ bool ImGui::BeginMenuBar() // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); + ImRect clip_rect(ImFloor(bar_rect.Min.x + window->WindowBorderSize + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize)) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); @@ -5931,8 +5931,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG const float y = tab_bar->BarRect.Max.y - 1.0f; if (dock_node != NULL) { - const float separator_min_x = dock_node->Pos.x; - const float separator_max_x = dock_node->Pos.x + dock_node->Size.x; + const float separator_min_x = dock_node->Pos.x + window->WindowBorderSize; + const float separator_max_x = dock_node->Pos.x + dock_node->Size.x - window->WindowBorderSize; window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); } else From a8277ca873c809e6ecd1a374a786f7b0ac8caca7 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 20:04:08 +0100 Subject: [PATCH 167/195] Reoder Python bindings --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 62934c42..afdef66c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -126,7 +126,7 @@ Languages: (third-party bindings) - Odin: [odin-dear_imgui](https://github.com/ThisDrunkDane/odin-dear_imgui) - Pascal: [imgui-pas](https://github.com/dpethes/imgui-pas) - PureBasic: [pb-cimgui](https://github.com/hippyau/pb-cimgui) -- Python [CyImGui](https://github.com/chromy/cyimgui) or [pyimgui](https://github.com/swistakm/pyimgui) +- Python: [pyimgui](https://github.com/swistakm/pyimgui) or [CyImGui](https://github.com/chromy/cyimgui) - Ruby: [ruby-imgui](https://github.com/vaiorabbit/ruby-imgui) - Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs) or [imgui-rust](https://github.com/nsf/imgui-rust) - Swift [swift-imgui](https://github.com/mnmly/Swift-imgui) From e55678adec78d9cbd90b558ac936a0d7e6a88013 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 24 Jan 2019 18:31:31 +0100 Subject: [PATCH 168/195] Update README.md (changed e-mail address) --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index afdef66c..ba9acc0c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,7 @@ Individuals/hobbyists: support continued maintenance and development via the mon
  [![Patreon](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/patreon_01.png)](http://www.patreon.com/imgui) Individuals/hobbyists: support continued maintenance and development via PayPal: -
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) +
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S) Businesses: support continued maintenance and development via support contracts or sponsoring:
  _E-mail: omarcornut at gmail dot com_ @@ -289,7 +289,7 @@ Individuals/hobbyists: support continued maintenance and development via the mon
  [![Patreon](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/patreon_01.png)](http://www.patreon.com/imgui) Individuals/hobbyists: support continued maintenance and development via PayPal: -
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) +
  [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S) Businesses: support continued maintenance and development via support contracts or sponsoring:
  _E-mail: omarcornut at gmail dot com_ From 737a3644fc6249d7bf53d3e74120dde1ac226e41 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 14:57:07 +0100 Subject: [PATCH 169/195] Removed trailing spaces (docking branch) --- docs/CHANGELOG.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1fd983b9..e146fb25 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,11 +53,11 @@ HOW TO UPDATE? Breaking Changes: -- IMPORTANT: When multi-viewports are enabled (with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable), +- IMPORTANT: When multi-viewports are enabled (with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable), all coordinates/positions will be in your natural OS coordinates space. It means that: - - Reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are _probably_ not what you want anymore. + - Reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are _probably_ not what you want anymore. Use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos). - - Likewise io.MousePos and GetMousePos() will use OS coordinates. + - Likewise io.MousePos and GetMousePos() will use OS coordinates. If you query mouse positions to interact with non-imgui coordinates you will need to offset them. e.g. subtract GetWindowViewport()->Pos. - IO: Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. @@ -72,7 +72,7 @@ Other changes: - Added GetMainViewport(). - Added GetWindowViewport(), SetNextWindowViewport(). - Added GetWindowDpiScale(). -- Added GetOverlayDrawList(ImGuiViewport* viewport). +- Added GetOverlayDrawList(ImGuiViewport* viewport). The no-parameter version of GetOverlayDrawList() return the overlay for the current window's viewport. - Added UpdatePlatformWindows(), RenderPlatformWindows(), DestroyPlatformWindows() for usage for application core. - Added FindViewportByID(), FindViewportByPlatformHandle() for usage by back-ends. @@ -82,7 +82,7 @@ Other changes: - Added ImGuiViewport structure, ImGuiViewportFlags flags. - Added ImGuiWindowClass and SetNextWindowClass() for passing viewport related hints to the OS/platform back-end. - Examples: Renderer: OpenGL2, OpenGL3, DirectX11, DirectX12, Vulkan: Added support for multi-viewports. -- Examples: Platforms: Win32, GLFW, SDL2: Added support for multi-viewports. +- Examples: Platforms: Win32, GLFW, SDL2: Added support for multi-viewports. Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117. @@ -518,7 +518,7 @@ VIEWPORT BRANCH - Viewport: Added support for multi-viewport [...] blah blah - Viewport: Rendering: the ImDrawData structure now contains 'DisplayPos' and 'DisplaySize' fields. To support multi-viewport, you need to use those values when creating your orthographic projection matrix. Use 'draw_data->DisplaySize' instead of 'io.DisplaySize', and 'draw_data->DisplayPos' instead of (0,0) as the upper-left point. - You also need to subtract 'draw_data->DisplayPos' from your scissor rectangles, as scissor rectangles are specified in the space of your target viewport. + You also need to subtract 'draw_data->DisplayPos' from your scissor rectangles, as scissor rectangles are specified in the space of your target viewport. - Examples: Back-ends have been refactored to separate the platform code (e.g. Win32, Glfw, SDL2) from the renderer code (e.g. DirectX11, OpenGL3, Vulkan). before: imgui_impl_dx11.cpp --> after: imgui_impl_win32.cpp + imgui_impl_dx11.cpp before: imgui_impl_dx12.cpp --> after: imgui_impl_win32.cpp + imgui_impl_dx12.cpp @@ -533,7 +533,7 @@ VIEWPORT BRANCH amount of redundancy accross files was becoming too difficult to maintain. - Some frameworks (such as the Allegro, Marmalade) handle both the "platform" and "rendering" part, and your custom engine may as well. - Each example still has its own main.cpp which you may refer you to understand how to initialize and glue everything together. - - Examples: Win32: Added DPI-related helpers to access DPI features _without_ requiring the latest Windows SDK at compile time, and _without_ requiring Windows 10 at runtime. + - Examples: Win32: Added DPI-related helpers to access DPI features _without_ requiring the latest Windows SDK at compile time, and _without_ requiring Windows 10 at runtime. - Examples: Platforms currently supporting multi-viewport: Win32, Glfw, SDL2. - Examples: Renderers currently supporting multi-viewport: DirectX10, DirectX11, OpenGL2, OpenGL3, Vulkan (WIP). - Examples: All imgui_impl_xxx files now have an individual Changelog at the top of the file, making it easier to follow how back-ends are evolving. From 20bc06af70a9b9189d37812a160af4c5ff9057f8 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 15:44:57 +0100 Subject: [PATCH 170/195] Added PushID(size_t sz) helper (may not be useful/meaningful for non C/C++ languages). --- docs/CHANGELOG.txt | 1 + imgui.cpp | 7 +++++++ imgui.h | 1 + 3 files changed, 9 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bd13b790..21966ac7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,6 +37,7 @@ Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. +- Added PushID(size_t sz) helper (may not be useful/meaningful for non C/C++ languages). - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - ImGuiTextBuffer: Added append() function (unformatted). diff --git a/imgui.cpp b/imgui.cpp index e94b8fac..c5c6f10d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6450,6 +6450,13 @@ void ImGui::PushID(const void* ptr_id) window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); } +void ImGui::PushID(size_t int_id) +{ + const void* ptr_id = (void*)int_id; + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); +} + void ImGui::PushID(int int_id) { const void* ptr_id = (void*)(intptr_t)int_id; diff --git a/imgui.h b/imgui.h index 609823fa..1ba4cac9 100644 --- a/imgui.h +++ b/imgui.h @@ -357,6 +357,7 @@ namespace ImGui IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(size_t int_id); // push pointer into the ID stack (will hash integer). IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). IMGUI_API void PopID(); // pop from the ID stack. IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself From c3c2cd1e82cca5da0d4e4fd5824f735a5ba8514c Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 15:27:49 +0100 Subject: [PATCH 171/195] Fix various XCode and PVS-Studio static analyzer warnings (#2309) --- imgui.cpp | 25 ++++++++++++++----------- imgui.h | 2 +- imgui_demo.cpp | 11 ++++++----- imgui_draw.cpp | 1 + imgui_internal.h | 2 +- imgui_widgets.cpp | 6 +++--- imstb_textedit.h | 1 - imstb_truetype.h | 12 +++++++++--- 8 files changed, 35 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c5c6f10d..c6f71bcf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4039,7 +4039,8 @@ int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_ int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) { ImGuiContext& g = *GImGui; - if (key_index < 0) return false; + if (key_index < 0) + return 0; IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); const float t = g.IO.KeysDownDuration[key_index]; return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate); @@ -4048,7 +4049,8 @@ int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_r bool ImGui::IsKeyPressed(int user_key_index, bool repeat) { ImGuiContext& g = *GImGui; - if (user_key_index < 0) return false; + if (user_key_index < 0) + return false; IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); const float t = g.IO.KeysDownDuration[user_key_index]; if (t == 0.0f) @@ -4139,13 +4141,12 @@ ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() return g.IO.MousePos; } -// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) { - if (mouse_pos == NULL) - mouse_pos = &GImGui->IO.MousePos; const float MOUSE_INVALID = -256000.0f; - return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; } // Return the delta from the initial clicking position. @@ -4819,7 +4820,10 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) + { + IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); window->RootWindowForNav = window->RootWindowForNav->ParentWindow; + } } // Push a new ImGui window to add widgets to. @@ -5082,7 +5086,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Position child window if (flags & ImGuiWindowFlags_ChildWindow) { - IM_ASSERT(parent_window->Active); + IM_ASSERT(parent_window && parent_window->Active); window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) @@ -9283,7 +9287,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) { ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (ImGui::IsItemHovered()) @@ -9352,12 +9356,11 @@ void ImGui::ShowMetricsWindow(bool* p_open) static void NodeTabBar(ImGuiTabBar* tab_bar) { - // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernable strings. + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. char buf[256]; char* p = buf; const char* buf_end = buf + IM_ARRAYSIZE(buf); - p += ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", - tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); + ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); if (ImGui::TreeNode(tab_bar, "%s", buf)) { for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) diff --git a/imgui.h b/imgui.h index 1ba4cac9..25aa872b 100644 --- a/imgui.h +++ b/imgui.h @@ -1945,7 +1945,7 @@ struct ImFontGlyphRangesBuilder { ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) - ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 32); memset(UsedChars.Data, 0, 0x10000 / 32); } + ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / sizeof(int)); memset(UsedChars.Data, 0, 0x10000 / sizeof(int)); } bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array void AddChar(ImWchar c) { SetBit(c); } // Add character diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9da96813..d3257493 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -879,12 +879,13 @@ static void ShowDemoWindowWidgets() ImGui::PushID(i); if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) { + // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary. int x = i % 4; int y = i / 4; - if (x > 0) { selected[i - 1] ^= 1; } - if (x < 3) { selected[i + 1] ^= 1; } - if (y > 0) { selected[i - 4] ^= 1; } - if (y < 3) { selected[i + 4] ^= 1; } + if (x > 0 && i > 0) { selected[i - 1] ^= 1; } + if (x < 3 && i < 15) { selected[i + 1] ^= 1; } + if (y > 0 && i > 3) { selected[i - 4] ^= 1; } + if (y < 3 && i < 12) { selected[i + 4] ^= 1; } } if ((i % 4) < 3) ImGui::SameLine(); ImGui::PopID(); @@ -3093,7 +3094,7 @@ struct ExampleAppConsole // Portable helpers static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } - static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); } + static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); } static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; } void ClearLog() diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bd44e159..046600a0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2063,6 +2063,7 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) { stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; + IM_ASSERT(pack_context != NULL); ImVector& user_rects = atlas->CustomRects; IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. diff --git a/imgui_internal.h b/imgui_internal.h index cb09bf29..92b3b96d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -183,7 +183,7 @@ IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* f IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API const char* ImParseFormatFindStart(const char* format); IMGUI_API const char* ImParseFormatFindEnd(const char* format); -IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, int buf_size); +IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); // Helpers: ImVec2/ImVec4 operators diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3fd90fd5..c4cb37a4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2577,7 +2577,7 @@ const char* ImParseFormatFindEnd(const char* fmt) // fmt = "%.3f" -> return fmt // fmt = "hello %.3f" -> return fmt + 6 // fmt = "%.3f hello" -> return buf written with "%.3f" -const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size) +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) { const char* fmt_start = ImParseFormatFindStart(fmt); if (fmt_start[0] != '%') @@ -2585,7 +2585,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_siz const char* fmt_end = ImParseFormatFindEnd(fmt_start); if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. return fmt_start; - ImStrncpy(buf, fmt_start, ImMin((int)(fmt_end + 1 - fmt_start), buf_size)); + ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); return buf; } @@ -6427,7 +6427,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Render tab label, process close button const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id); - if (just_closed) + if (just_closed && p_open != NULL) { *p_open = false; TabBarCloseTab(tab_bar, tab); diff --git a/imstb_textedit.h b/imstb_textedit.h index 9e12469b..27e34f74 100644 --- a/imstb_textedit.h +++ b/imstb_textedit.h @@ -563,7 +563,6 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s // now scan to find xpos find->x = r.x0; - i = 0; for (i=0; first+i < n; ++i) find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); } diff --git a/imstb_truetype.h b/imstb_truetype.h index f65deb50..e6162fab 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -1,3 +1,6 @@ +// [ImGui] this is a slightly modified version of stb_truetype.h 1.19. Those changes would need to be pushed into nothings/stb +// grep for [ImGui] to find the changes. + // stb_truetype.h - v1.19 - public domain // authored from 2009-2016 by Sean Barrett / RAD Game Tools // @@ -2368,7 +2371,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - classDefTable = classDef1ValueArray + 2 * glyphCount; + // [ImGui: commented to fix static analyzer warning] + //classDefTable = classDef1ValueArray + 2 * glyphCount; } break; case 2: { @@ -2392,7 +2396,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) return (stbtt_int32)ttUSHORT(classRangeRecord + 4); } - classDefTable = classRangeRecords + 6 * classRangeCount; + // [ImGui: commented to fix static analyzer warning] + //classDefTable = classRangeRecords + 6 * classRangeCount; } break; default: { @@ -3024,6 +3029,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, dx = -dx; dy = -dy; t = x0, x0 = xb, xb = t; + (void)dx; // [ImGui: fix static analyzer warning] } x1 = (int) x_top; @@ -4253,7 +4259,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex int winding = 0; orig[0] = x; - orig[1] = y; + //orig[1] = y; // [ImGui] commmented double assignment without reading // make sure y never passes through a vertex of the shape y_frac = (float) STBTT_fmod(y, 1.0f); From ee3b4f2bf17c35bcd368db6fde0195e59a2dc8d8 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 16:23:23 +0100 Subject: [PATCH 172/195] Using IM_UNUSED() macro. --- imgui.cpp | 12 ++++++------ imgui.h | 3 ++- imgui_widgets.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c6f71bcf..2e097e85 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1063,11 +1063,11 @@ ImGuiContext* GImGui = NULL; // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. // Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS -static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); } -static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); } +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } #else -static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; } -static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); } +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } #endif static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; @@ -2706,9 +2706,9 @@ void ImGui::MarkItemEdited(ImGuiID id) { // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data. - (void)id; // Avoid unused variable warnings when asserts are compiled out. ImGuiContext& g = *GImGui; IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); + IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); g.ActiveIdHasBeenEdited = true; g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; @@ -6918,7 +6918,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla void ImGui::EndPopup() { - ImGuiContext& g = *GImGui; (void)g; + ImGuiContext& g = *GImGui; IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls IM_ASSERT(g.BeginPopupStack.Size > 0); diff --git a/imgui.h b/imgui.h index 25aa872b..ced75d40 100644 --- a/imgui.h +++ b/imgui.h @@ -72,6 +72,7 @@ Index of this file: #endif #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++. +#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. // Warnings #if defined(__clang__) @@ -1494,7 +1495,7 @@ namespace ImGui // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } - static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { (void)on_edge; (void)outward; IM_ASSERT(0); return pos; } + static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { IM_UNUSED(on_edge); IM_UNUSED(outward); IM_ASSERT(0); return pos; } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) static inline void ShowTestWindow() { return ShowDemoWindow(); } static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c4cb37a4..fac87c1d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6476,9 +6476,9 @@ ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) { // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. - (void)flags; ImGuiContext& g = *GImGui; const float width = bb.GetWidth(); + IM_UNUSED(flags); IM_ASSERT(width > 0.0f); const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f)); float y1 = bb.Min.y + 1.0f; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 1b3843b3..f7523644 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -569,8 +569,8 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns } // Default memory allocators -static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { (void)user_data; return ImGui::MemAlloc(size); } -static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { (void)user_data; ImGui::MemFree(ptr); } +static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return ImGui::MemAlloc(size); } +static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); ImGui::MemFree(ptr); } // Current memory allocators static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc; From 4e8e177cac657428fe511cb3a8b942b1654bd7f4 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 16:35:48 +0100 Subject: [PATCH 173/195] Persistently fixing some PVS-Studio static analyzer false positive warnings. --- imgui_demo.cpp | 2 +- imgui_draw.cpp | 4 ++-- imgui_widgets.cpp | 4 ++-- imstb_truetype.h | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d3257493..0ff6fb4a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -882,7 +882,7 @@ static void ShowDemoWindowWidgets() // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary. int x = i % 4; int y = i / 4; - if (x > 0 && i > 0) { selected[i - 1] ^= 1; } + if (x > 0) { selected[i - 1] ^= 1; } if (x < 3 && i < 15) { selected[i + 1] ^= 1; } if (y > 0 && i > 3) { selected[i - 4] ^= 1; } if (y < 3 && i < 12) { selected[i + 4] ^= 1; } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 046600a0..b73299b1 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -689,7 +689,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 PrimReserve(idx_count, vtx_count); // Temporary buffer - ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); + ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630 ImVec2* temp_points = temp_normals + points_count; for (int i1 = 0; i1 < count; i1++) @@ -880,7 +880,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun } // Compute normals - ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); + ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630 for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) { const ImVec2& p0 = points[i0]; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fac87c1d..60aebb2a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4007,7 +4007,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag { if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) { - memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 value_changed = true; } if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) @@ -5485,7 +5485,7 @@ bool ImGui::BeginMainMenuBar() End(); return false; } - return true; + return true; //-V1020 } void ImGui::EndMainMenuBar() diff --git a/imstb_truetype.h b/imstb_truetype.h index e6162fab..0b65350a 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -1828,7 +1828,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s if (comp_verts) STBTT_free(comp_verts, info->userdata); return 0; } - if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595 STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); if (vertices) STBTT_free(vertices, info->userdata); vertices = tmp; @@ -2199,7 +2199,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st } break; default: - if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) + if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560 return STBTT__CSERR("reserved operator"); // push immediate From f56d9b74cc3bac4e3f2d89ed1a559955d080b5b8 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 16:37:02 +0100 Subject: [PATCH 174/195] Nav: Removed unnecessary test (always failing). --- imgui.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e097e85..fd270b51 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7610,9 +7610,8 @@ static void ImGui::NavUpdate() NavUpdateWindowing(); // Set output flags for user application - // FIXME: g.NavInitRequest is always false at this point, investigate the intent of operation done here. g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); - g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest; + g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); // Process NavCancel input (to close a popup, get back to parent, clear focus) if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) From b26ac92a122b86202bf0763eec397d2aa72b572f Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 16:43:56 +0100 Subject: [PATCH 175/195] Revert "Added PushID(size_t sz) helper (may not be useful/meaningful for non C/C++ languages)." This reverts commit 20bc06af70a9b9189d37812a160af4c5ff9057f8. --- docs/CHANGELOG.txt | 1 - imgui.cpp | 7 ------- imgui.h | 1 - 3 files changed, 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 21966ac7..bd13b790 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,7 +37,6 @@ Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. -- Added PushID(size_t sz) helper (may not be useful/meaningful for non C/C++ languages). - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - ImGuiTextBuffer: Added append() function (unformatted). diff --git a/imgui.cpp b/imgui.cpp index fd270b51..35b89ae5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6454,13 +6454,6 @@ void ImGui::PushID(const void* ptr_id) window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); } -void ImGui::PushID(size_t int_id) -{ - const void* ptr_id = (void*)int_id; - ImGuiWindow* window = GImGui->CurrentWindow; - window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); -} - void ImGui::PushID(int int_id) { const void* ptr_id = (void*)(intptr_t)int_id; diff --git a/imgui.h b/imgui.h index ced75d40..c12f9739 100644 --- a/imgui.h +++ b/imgui.h @@ -358,7 +358,6 @@ namespace ImGui IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). - IMGUI_API void PushID(size_t int_id); // push pointer into the ID stack (will hash integer). IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). IMGUI_API void PopID(); // pop from the ID stack. IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself From 8a605354ef890601ea03888e9e60b9b7284bfe95 Mon Sep 17 00:00:00 2001 From: Marc-Alexandre Espiaut Date: Sun, 27 Jan 2019 21:59:48 +0100 Subject: [PATCH 176/195] Replacing one of the third-party Python bindings. (#2312) Removing the unmaintained CyImGui (only 7 commits, last one made in 2015) and replacing it with bimpy. --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index ba9acc0c..cfeef09c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -126,7 +126,7 @@ Languages: (third-party bindings) - Odin: [odin-dear_imgui](https://github.com/ThisDrunkDane/odin-dear_imgui) - Pascal: [imgui-pas](https://github.com/dpethes/imgui-pas) - PureBasic: [pb-cimgui](https://github.com/hippyau/pb-cimgui) -- Python: [pyimgui](https://github.com/swistakm/pyimgui) or [CyImGui](https://github.com/chromy/cyimgui) +- Python: [pyimgui](https://github.com/swistakm/pyimgui) or [bimpy](https://github.com/podgorskiy/bimpy) - Ruby: [ruby-imgui](https://github.com/vaiorabbit/ruby-imgui) - Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs) or [imgui-rust](https://github.com/nsf/imgui-rust) - Swift [swift-imgui](https://github.com/mnmly/Swift-imgui) From 13ca2fe84564c64b898e00824eced63fb47d256d Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 23:30:44 +0100 Subject: [PATCH 177/195] Silence XCode static analysis false positive (#2309) --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 35b89ae5..61339fd7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4144,6 +4144,9 @@ ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) { + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); const float MOUSE_INVALID = -256000.0f; ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; From 8a4422b2fab4ec045ac04ede593845c47601fbb1 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Jan 2019 23:54:17 +0100 Subject: [PATCH 178/195] Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 15 ++++++++++++++- imgui_demo.cpp | 17 ++++++++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bd13b790..d30b353b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,6 +36,7 @@ HOW TO UPDATE? Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. +- Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 61339fd7..8d859351 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6837,8 +6837,21 @@ void ImGui::CloseCurrentPopup() int popup_idx = g.BeginPopupStack.Size - 1; if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) return; - while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) + + // Closing a menu closes its top-most parent popup (unless a modal) + while (popup_idx > 0) + { + ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; + ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; + bool close_parent = false; + if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) + if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) + close_parent = true; + if (!close_parent) + break; popup_idx--; + } + //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); ClosePopupToLevel(popup_idx, true); // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0ff6fb4a..6fbde69a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2171,13 +2171,24 @@ static void ShowDemoWindowPopups() if (ImGui::Button("Stacked modals..")) ImGui::OpenPopup("Stacked 1"); - if (ImGui::BeginPopupModal("Stacked 1")) + if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Dummy menu item")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); + + // Testing behavior of widgets stacking their own regular popups over the modal. static int item = 1; - ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; - ImGui::ColorEdit4("color", color); // This is to test behavior of stacked regular popups over a modal + ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::ColorEdit4("color", color); if (ImGui::Button("Add another modal..")) ImGui::OpenPopup("Stacked 2"); From ed240c910bb1019a23c59806f7856bebe181cef7 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 29 Jan 2019 14:36:55 +0100 Subject: [PATCH 179/195] Demo: Fixed "Log" demo not initializing properly, leading to the first line not showing before a Clear. (#2318) [@bluescan] --- docs/CHANGELOG.txt | 1 + imgui_demo.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d30b353b..61b84a58 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,7 @@ Other Changes: - ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093) - ImFontAtlas: FreeType: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo] - ImFontAtlas: FreeType: Fixed using imgui_freetype.cpp in unity builds. (#2302) +- Demo: Fixed "Log" demo not initializing properly, leading to the first line not showing before a Clear. (#2318) [@bluescan] - Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6fbde69a..68dc8b1d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3397,6 +3397,12 @@ struct ExampleAppLog ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines bool ScrollToBottom; + ExampleAppLog() + { + ScrollToBottom = false; + Clear(); + } + void Clear() { Buf.clear(); From 2ccc6d2ed1dc1e54b4713e5ca6b9af082790f912 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 29 Jan 2019 15:40:18 +0100 Subject: [PATCH 180/195] Docking: Exposing extra flag in Configuration panel. Moved some forgotten Changelog entries at the right place. --- docs/CHANGELOG.txt | 46 +++++++++++----------------------------------- imgui.cpp | 4 ++-- imgui_demo.cpp | 3 +++ 3 files changed, 16 insertions(+), 37 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e146fb25..4237bf91 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -33,6 +33,8 @@ HOW TO UPDATE? DOCKING BRANCH (In Progress) ----------------------------------------------------------------------- +DOCKING FEATURES + - Added Docking system: [BETA] (#2109, #351) - Added ImGuiConfigFlags_DockingEnable flag to enable Docking. Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`. @@ -46,10 +48,7 @@ HOW TO UPDATE? - Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingEmptyBg colors. - Demo: Added "DockSpace" example app showcasing use of explicit dockspace nodes. - ------------------------------------------------------------------------ - VIEWPORT BRANCH (In Progress) ------------------------------------------------------------------------ +MULTI-VIEWPORT FEATURES (was previously 'viewport' branch, merged into 'docking') Breaking Changes: @@ -60,6 +59,10 @@ Breaking Changes: - Likewise io.MousePos and GetMousePos() will use OS coordinates. If you query mouse positions to interact with non-imgui coordinates you will need to offset them. e.g. subtract GetWindowViewport()->Pos. +- Render function: the ImDrawData structure now contains 'DisplayPos' and 'DisplaySize' fields. + To support multi-viewport, you need to use those values when creating your orthographic projection matrix. + Use 'draw_data->DisplaySize' instead of 'io.DisplaySize', and 'draw_data->DisplayPos' instead of (0,0) as the upper-left point. + You need to subtract 'draw_data->DisplayPos' from your scissor rectangles to convert them from global coordinates to frame-buffer coordinates. - IO: Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. - IO: Removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were marked obsoleted, used to clip within the (0,0)..(DisplaySize) range). @@ -84,6 +87,10 @@ Other changes: - Examples: Renderer: OpenGL2, OpenGL3, DirectX11, DirectX12, Vulkan: Added support for multi-viewports. - Examples: Platforms: Win32, GLFW, SDL2: Added support for multi-viewports. Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117. +- Examples: Win32: Added DPI-related helpers to access DPI features without requiring the latest Windows SDK at compile time, + and without requiring Windows 10 at runtime. +- Examples: Vulkan: Added various optional helpers in imgui_impl_vulkan.h (they are used for multi-viewport support) + to make the examples main.cpp easier to read. ----------------------------------------------------------------------- @@ -512,37 +519,6 @@ The gamepad/keyboard navigation branch (which has been in the work since July 20 Gamepad/keyboard navigation is still marked as Beta and has to be enabled explicitly. Various internal refactoring have also been done, as part of the navigation work and as part of the upcoming viewport/docking work. -VIEWPORT BRANCH -(IN PROGRESS, WILL MERGE INTO THE MAIN LISTS WHEN WE MERGE THE BRANCH) - - - Viewport: Added support for multi-viewport [...] blah blah - - Viewport: Rendering: the ImDrawData structure now contains 'DisplayPos' and 'DisplaySize' fields. To support multi-viewport, you need to use those values when - creating your orthographic projection matrix. Use 'draw_data->DisplaySize' instead of 'io.DisplaySize', and 'draw_data->DisplayPos' instead of (0,0) as the upper-left point. - You also need to subtract 'draw_data->DisplayPos' from your scissor rectangles, as scissor rectangles are specified in the space of your target viewport. - - Examples: Back-ends have been refactored to separate the platform code (e.g. Win32, Glfw, SDL2) from the renderer code (e.g. DirectX11, OpenGL3, Vulkan). - before: imgui_impl_dx11.cpp --> after: imgui_impl_win32.cpp + imgui_impl_dx11.cpp - before: imgui_impl_dx12.cpp --> after: imgui_impl_win32.cpp + imgui_impl_dx12.cpp - before: imgui_impl_glfw_gl3.cpp --> after: imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp - before: imgui_impl_glfw_vulkan.cpp --> after: imgui_impl_glfw.cpp + imgui_impl_vulkan.cpp - before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl2.cpp - before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp - etc. - - The idea is what we can now easily combine and maintain back-ends and reduce code redundancy. Integration of imgui into a new/custom engine may also - be easier as there is less overlap between "windowing / inputs" and "rendering" code, so you may study or grab one half of the code and not the other. - - This change was motivated by the fact that adding support for multi-viewport requires more work from the platform and renderer back-ends, and the - amount of redundancy accross files was becoming too difficult to maintain. - - Some frameworks (such as the Allegro, Marmalade) handle both the "platform" and "rendering" part, and your custom engine may as well. - - Each example still has its own main.cpp which you may refer you to understand how to initialize and glue everything together. - - Examples: Win32: Added DPI-related helpers to access DPI features _without_ requiring the latest Windows SDK at compile time, and _without_ requiring Windows 10 at runtime. - - Examples: Platforms currently supporting multi-viewport: Win32, Glfw, SDL2. - - Examples: Renderers currently supporting multi-viewport: DirectX10, DirectX11, OpenGL2, OpenGL3, Vulkan (WIP). - - Examples: All imgui_impl_xxx files now have an individual Changelog at the top of the file, making it easier to follow how back-ends are evolving. - - Examples: Vulkan: Added various optional helpers in imgui_impl_vulkan.h (they are used for multi-viewport support) to make the examples main.cpp easier to read. - - Examples: Allegro: Renamed imgui_impl_a5.xxx files to imgui_impl_allegro5.xxx, ImGui_ImplA5_** symbols to ImGui_ImplAllegro5_xxx. - - Examples: Vulkan+SDL: Added a Vulkan+SDL example. (#1367) [@gmueckl] - - Metrics: Added a "Show window begin order" checkbox to visualize the order windows are submitted. - - Internal: Settings: Added ReadCloseFn handler to be able to patch/alter a loaded object after all the fields are known. - Breaking Changes: - Obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). diff --git a/imgui.cpp b/imgui.cpp index 10038d5a..d4b76a13 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10697,10 +10697,9 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) IM_ASSERT(node->IsLeafNode()); IM_ASSERT(node->Windows.Size >= 1); - // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload. - // Otherwise delete the previous node by merging the other sibling back into the parent node. if (node->IsRootNode() || node->IsCentralNode) { + // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload. ImGuiDockNode* new_node = DockContextAddNode(ctx, 0); DockNodeMoveWindows(new_node, node); DockSettingsMoveDockReferencesInInactiveWindow(node->ID, new_node->ID); @@ -10710,6 +10709,7 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) } else { + // Otherwise delete the previous node by merging the other sibling back into the parent node. IM_ASSERT(node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node); int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1; node->ParentNode->ChildNodes[index_in_parent] = NULL; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a78075fb..c807f5d2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -355,6 +355,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); ShowHelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)"); ImGui::Checkbox("io.ConfigDockingTabBarOnSingleWindows", &io.ConfigDockingTabBarOnSingleWindows); ImGui::SameLine(); ShowHelpMarker("Create a docking node and tab-bar on single floating windows."); + ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload); + ImGui::SameLine(); ShowHelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge."); ImGui::Unindent(); } @@ -387,6 +389,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Backend Flags")) { + ShowHelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities."); ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying the back-end flags. ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); From 86d3bba157a59605c40fe221179666a3eea1b28d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 29 Jan 2019 15:40:38 +0100 Subject: [PATCH 181/195] Added ImGuiDockNodeFlags_AutoHideTabBar. (#2109) --- imgui.cpp | 11 +++++++++-- imgui.h | 5 +++-- imgui_demo.cpp | 1 + imgui_internal.h | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d4b76a13..2ec30c32 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10743,7 +10743,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) InitFromFirstWindowPosSize = InitFromFirstWindowViewport = false; IsVisible = true; IsFocused = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false; - WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarToggle = false; + WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false; } ImGuiDockNode::~ImGuiDockNode() @@ -10774,6 +10774,7 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL); node->Windows.push_back(window); + node->WantHiddenTabBarUpdate = true; window->DockNode = node; window->DockId = node->ID; window->DockIsActive = (node->Windows.Size > 1); @@ -10841,6 +10842,7 @@ static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window node->VisibleWindow = NULL; // Remove tab and possibly tab bar + node->WantHiddenTabBarUpdate = true; if (node->TabBar) { TabBarRemoveTab(node->TabBar, window->ID); @@ -11033,6 +11035,11 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod window_n--; } + // Auto-hide tab bar option + if (node->WantHiddenTabBarUpdate && node->Windows.Size == 1 && (node->Flags & ImGuiDockNodeFlags_AutoHideTabBar) && !node->IsHiddenTabBar) + node->WantHiddenTabBarToggle = true; + node->WantHiddenTabBarUpdate = false; + // Apply toggles at a single point of the frame (here!) if (node->Windows.Size > 1) node->IsHiddenTabBar = false; @@ -12863,7 +12870,7 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window) else allow_null_target_node = true; // Dock into a regular window - const ImRect explicit_target_rect = (target_node && target_node->TabBar) ? target_node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight())); + const ImRect explicit_target_rect = (target_node && target_node->TabBar && !target_node->IsHiddenTabBar) ? target_node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight())); const bool is_explicit_target = g.IO.ConfigDockingWithShift || IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max); // Preview docking request and find out split direction/ratio diff --git a/imgui.h b/imgui.h index 7ec77c49..00f8cd5b 100644 --- a/imgui.h +++ b/imgui.h @@ -879,7 +879,8 @@ enum ImGuiDockNodeFlags_ ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 3, // Disable docking inside the Central Node, which will be always kept empty. //ImGuiDockNodeFlags_NoLayoutChanges = 1 << 4, // Disable adding/removing nodes interactively. Useful with programatically setup dockspaces. ImGuiDockNodeFlags_NoResize = 1 << 5, // Disable resizing child nodes using the splitter/separators. Useful with programatically setup dockspaces. - ImGuiDockNodeFlags_PassthruDockspace = 1 << 6 // 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. + ImGuiDockNodeFlags_PassthruDockspace = 1 << 6, // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. + ImGuiDockNodeFlags_AutoHideTabBar = 1 << 7 // Tab bar will automatically hide when there is a single window in the dock node. }; // Flags for ImGui::IsWindowFocused() @@ -1373,7 +1374,7 @@ struct ImGuiIO bool ConfigDockingNoSplit; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars. bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space) bool ConfigDockingTabBarOnSingleWindows; // = false // [BETA] Make every single floating window display within a docking node. - bool ConfigDockingTransparentPayload;// = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport can be synced. Best used with ImGuiConfigFlags_ViewportsNoMerge. + bool ConfigDockingTransparentPayload;// = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge. // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c807f5d2..9c082636 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4100,6 +4100,7 @@ void ShowExampleAppDockSpace(bool* p_open) if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (opt_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) opt_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; if (ImGui::MenuItem("Flag: NoResize", "", (opt_flags & ImGuiDockNodeFlags_NoResize) != 0)) opt_flags ^= ImGuiDockNodeFlags_NoResize; if (ImGui::MenuItem("Flag: PassthruDockspace", "", (opt_flags & ImGuiDockNodeFlags_PassthruDockspace) != 0)) opt_flags ^= ImGuiDockNodeFlags_PassthruDockspace; + if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (opt_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) opt_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; ImGui::Separator(); if (ImGui::MenuItem("Close DockSpace", NULL, false, p_open != NULL)) *p_open = false; diff --git a/imgui_internal.h b/imgui_internal.h index 7fb41c28..6ee34b71 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -854,6 +854,7 @@ struct ImGuiDockNode bool WantCloseAll :1; // Set when closing all tabs at once. bool WantLockSizeOnce :1; bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created host window + bool WantHiddenTabBarUpdate :1; bool WantHiddenTabBarToggle :1; ImGuiDockNode(ImGuiID id); From 37fb531d1c8d4a1f4fa34e1e8ba4d8c9ddfda1f2 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 29 Jan 2019 18:54:56 +0100 Subject: [PATCH 182/195] Docking: Comments and tidying up (should be no-op) --- imgui.cpp | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2ec30c32..cbd9a3a1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10062,7 +10062,7 @@ void ImGui::EndDragDropTarget() // Docking: ImGuiDockNode // Docking: ImGuiDockNode Tree manipulation functions // Docking: Public Functions (SetWindowDock, DockSpace) -// Docking: Public Builder Functions +// Docking: Builder Functions // Docking: Begin/End Functions (called from Begin/End) // Docking: Settings //----------------------------------------------------------------------------- @@ -10162,9 +10162,9 @@ namespace ImGui static void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); static void DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx); static ImGuiDockNode* DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id); - static void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_refs); // Set root_id==0 to clear all + static void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_refs); // Use root_id==0 to clear all static void DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count); - static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all + static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all // ImGuiDockNode static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar); @@ -10197,8 +10197,8 @@ namespace ImGui static ImGuiDockNode* DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node); // Settings - static void DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id); - static void DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count); + static void DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id); + static void DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count); static ImGuiDockNodeSettings* DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id); static void* DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); static void DockSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); @@ -10212,8 +10212,8 @@ namespace ImGui // or we always hold the entire docking node tree. Nodes are frequently hidden, e.g. if the window(s) or child nodes they host are not active. // At boot time only, we run a simple GC to remove nodes that have no references. // Because dock node settings (which are small, contiguous structures) are always mirrored by their corresponding dock nodes (more complete structures), -// we can also very easily recreate the nodes from scratch given the settings data (this is what DockContextRebuild() does). -// This is convenient as docking reconfiguration can be implemented by mostly poking at the simpler setttings data. +// we can also very easily recreate the nodes from scratch given the settings data (this is what DockContextRebuild() does). +// This is convenient as docking reconfiguration can be implemented by mostly poking at the simpler settings data. //----------------------------------------------------------------------------- void ImGui::DockContextInitialize(ImGuiContext* ctx) @@ -10280,8 +10280,9 @@ void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx) DockContextClearNodes(ctx, 0, true); return; } + + // Setting NoSplit at runtime merges all nodes if (g.IO.ConfigDockingNoSplit) - { for (int n = 0; n < dc->Nodes.Data.Size; n++) if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) if (node->IsRootNode() && node->IsSplitNode()) @@ -10289,8 +10290,8 @@ void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx) DockBuilderRemoveNodeChildNodes(node->ID); //dc->WantFullRebuild = true; } - } - + + // Process full rebuild #if 0 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C))) dc->WantFullRebuild = true; @@ -10342,7 +10343,7 @@ static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID static ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx) { // Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used) - // FIXME-OPT: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster. + // FIXME-OPT FIXME-DOCKING: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster. ImGuiID id = 0x0001; while (DockContextFindNodeByID(ctx, id) != NULL) id++; @@ -10400,11 +10401,11 @@ static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const voi return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a); } -// Pre C++0x doesn't allow us to use a local type (without linkage) as template parameter, so we moved this here. +// Pre C++0x doesn't allow us to use a function-local type (without linkage) as template parameter, so we moved this here. struct ImGuiDockContextPruneNodeData { - int CountWindows, CountChildWindows, CountChildNodes; - ImGuiID RootID; + int CountWindows, CountChildWindows, CountChildNodes; + ImGuiID RootID; ImGuiDockContextPruneNodeData() { CountWindows = CountChildWindows = CountChildNodes = 0; RootID = 0; } }; @@ -10453,7 +10454,7 @@ static void ImGui::DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx) remove |= (data_root->CountChildWindows == 0); if (remove) { - DockSettingsRemoveReferencesToNodes(&settings->ID, 1); + DockSettingsRemoveNodeReferences(&settings->ID, 1); settings->ID = 0; } } @@ -10464,24 +10465,24 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc // Build nodes for (int node_n = 0; node_n < node_settings_count; node_n++) { - ImGuiDockNodeSettings* node_settings = &node_settings_array[node_n]; - if (node_settings->ID == 0) + ImGuiDockNodeSettings* settings = &node_settings_array[node_n]; + if (settings->ID == 0) continue; - ImGuiDockNode* node = DockContextAddNode(ctx, node_settings->ID); - node->ParentNode = node_settings->ParentID ? DockContextFindNodeByID(ctx, node_settings->ParentID) : NULL; - node->Pos = ImVec2(node_settings->Pos.x, node_settings->Pos.y); - node->Size = ImVec2(node_settings->Size.x, node_settings->Size.y); - node->SizeRef = ImVec2(node_settings->SizeRef.x, node_settings->SizeRef.y); + ImGuiDockNode* node = DockContextAddNode(ctx, settings->ID); + node->ParentNode = settings->ParentID ? DockContextFindNodeByID(ctx, settings->ParentID) : NULL; + node->Pos = ImVec2(settings->Pos.x, settings->Pos.y); + node->Size = ImVec2(settings->Size.x, settings->Size.y); + node->SizeRef = ImVec2(settings->SizeRef.x, settings->SizeRef.y); if (node->ParentNode && node->ParentNode->ChildNodes[0] == NULL) node->ParentNode->ChildNodes[0] = node; else if (node->ParentNode && node->ParentNode->ChildNodes[1] == NULL) node->ParentNode->ChildNodes[1] = node; - node->SelectedTabID = node_settings->SelectedTabID; - node->SplitAxis = node_settings->SplitAxis; - if (node_settings->IsDockSpace) + node->SelectedTabID = settings->SelectedTabID; + node->SplitAxis = settings->SplitAxis; + if (settings->IsDockSpace) node->Flags |= ImGuiDockNodeFlags_Dockspace; - node->IsCentralNode = node_settings->IsCentralNode != 0; - node->IsHiddenTabBar = node_settings->IsHiddenTabBar != 0; + node->IsCentralNode = settings->IsCentralNode != 0; + node->IsHiddenTabBar = settings->IsHiddenTabBar != 0; // Bind host window immediately if it already exist (in case of a rebuild) // This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set. @@ -10576,7 +10577,6 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) } // FIXME-DOCK: When we are trying to dock an existing single-window node into a loose window, transfer Node ID as well - if (target_node) IM_ASSERT(target_node->LastFrameAlive < g.FrameCount); if (target_node && target_window && target_node == target_window->DockNodeAsHost) @@ -10601,15 +10601,11 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) { // Split into one, one side will be our payload node unless we are dropping a loose window const ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; - const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0; + const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0; // Current contents will be moved to the opposite side const float split_ratio = req->DockSplitRatio; DockNodeTreeSplit(ctx, target_node, split_axis, split_inheritor_child_idx, split_ratio, payload_node); // payload_node may be NULL here! - ImGuiDockNode* inheritor_node = target_node->ChildNodes[split_inheritor_child_idx]; ImGuiDockNode* new_node = target_node->ChildNodes[split_inheritor_child_idx ^ 1]; new_node->HostWindow = target_node->HostWindow; - inheritor_node->IsCentralNode = target_node->IsCentralNode; - inheritor_node->IsHiddenTabBar = target_node->IsHiddenTabBar; - target_node->IsCentralNode = false; target_node = new_node; } target_node->IsHiddenTabBar = false; @@ -10640,7 +10636,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) IM_ASSERT(visible_node->TabBar->Tabs.Size > 0); DockNodeMoveWindows(target_node, visible_node); DockNodeMoveWindows(visible_node, target_node); - DockSettingsMoveDockReferencesInInactiveWindow(target_node->ID, visible_node->ID); + DockSettingsRenameNodeReferences(target_node->ID, visible_node->ID); } if (target_node->IsCentralNode) { @@ -10658,7 +10654,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) { const ImGuiID payload_dock_id = payload_node->ID; DockNodeMoveWindows(target_node, payload_node); - DockSettingsMoveDockReferencesInInactiveWindow(payload_dock_id, target_node->ID); + DockSettingsRenameNodeReferences(payload_dock_id, target_node->ID); } DockContextRemoveNode(ctx, payload_node, true); } @@ -10669,7 +10665,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) target_node->VisibleWindow = payload_window; DockNodeAddWindow(target_node, payload_window, true); if (payload_dock_id != 0) - DockSettingsMoveDockReferencesInInactiveWindow(payload_dock_id, target_node->ID); + DockSettingsRenameNodeReferences(payload_dock_id, target_node->ID); } } @@ -10702,7 +10698,7 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload. ImGuiDockNode* new_node = DockContextAddNode(ctx, 0); DockNodeMoveWindows(new_node, node); - DockSettingsMoveDockReferencesInInactiveWindow(node->ID, new_node->ID); + DockSettingsRenameNodeReferences(node->ID, new_node->ID); for (int n = 0; n < new_node->Windows.Size; n++) UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL); new_node->WantMouseMove = true; @@ -11911,6 +11907,10 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG DockNodeMoveWindows(parent_node->ChildNodes[split_inheritor_child_idx], parent_node); DockNodeTreeUpdatePosSize(parent_node, parent_node->Pos, parent_node->Size); + + child_inheritor->IsCentralNode = parent_node->IsCentralNode; + child_inheritor->IsHiddenTabBar = parent_node->IsHiddenTabBar; + parent_node->IsCentralNode = false; } void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child) @@ -11931,12 +11931,12 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG if (child_0) { DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows - DockSettingsMoveDockReferencesInInactiveWindow(child_0->ID, parent_node->ID); + DockSettingsRenameNodeReferences(child_0->ID, parent_node->ID); } if (child_1) { DockNodeMoveWindows(parent_node, child_1); - DockSettingsMoveDockReferencesInInactiveWindow(child_1->ID, parent_node->ID); + DockSettingsRenameNodeReferences(child_1->ID, parent_node->ID); } DockNodeApplyPosSizeToWindows(parent_node); parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false; @@ -12904,25 +12904,25 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window) // Docking: Settings //----------------------------------------------------------------------------- -static void ImGui::DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id) +static void ImGui::DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id) { ImGuiContext& g = *GImGui; for (int window_n = 0; window_n < g.Windows.Size; window_n++) { ImGuiWindow* window = g.Windows[window_n]; - if (window->DockId == old_dock_id && window->DockNode == NULL) - window->DockId = new_dock_id; + if (window->DockId == old_node_id && window->DockNode == NULL) + window->DockId = new_node_id; } for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++) // FIXME-OPT: We could remove this loop by storing the index in the map { ImGuiWindowSettings* window_settings = &g.SettingsWindows[settings_n]; - if (window_settings->DockId == old_dock_id) - window_settings->DockId = new_dock_id; + if (window_settings->DockId == old_node_id) + window_settings->DockId = new_node_id; } } // Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings -static void ImGui::DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count) +static void ImGui::DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count) { ImGuiContext& g = *GImGui; int found = 0; From aacf993ee15c4d168fb5528d8f78f4cb1767dc04 Mon Sep 17 00:00:00 2001 From: Francisco Gallego Date: Wed, 30 Jan 2019 10:19:40 +0100 Subject: [PATCH 183/195] ImStrncpy: Fixed -Wstringop-truncation warning on GCC8 (#2323) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 8d859351..4fd20a9e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1295,7 +1295,8 @@ int ImStrnicmp(const char* str1, const char* str2, size_t count) void ImStrncpy(char* dst, const char* src, size_t count) { if (count < 1) return; - strncpy(dst, src, count); + if (count > 1) + strncpy(dst, src, count-1); dst[count-1] = 0; } From 0a233a505d60869f952a29b92d183110ce66cda7 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Jan 2019 10:52:13 +0100 Subject: [PATCH 184/195] imgui-test: Added extra item info callbacks. Using nav_bb for interactions when possible. Comments, Demo tweaks. --- imgui.cpp | 10 ++++++---- imgui_demo.cpp | 18 +++++++++++------- imgui_internal.h | 2 +- imgui_widgets.cpp | 4 ++++ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4fd20a9e..320b6644 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1278,6 +1278,7 @@ ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, return proj_ca; } +// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. int ImStricmp(const char* str1, const char* str2) { int d; @@ -1294,10 +1295,11 @@ int ImStrnicmp(const char* str1, const char* str2, size_t count) void ImStrncpy(char* dst, const char* src, size_t count) { - if (count < 1) return; + if (count < 1) + return; if (count > 1) - strncpy(dst, src, count-1); - dst[count-1] = 0; + strncpy(dst, src, count - 1); + dst[count - 1] = 0; } char* ImStrdup(const char* str) @@ -2796,7 +2798,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) #ifdef IMGUI_ENABLE_TEST_ENGINE if (id != 0) - ImGuiTestEngineHook_ItemAdd(&g, bb, id); + ImGuiTestEngineHook_ItemAdd(&g, nav_bb_arg ? *nav_bb_arg : bb, id); #endif // Clipping test diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 68dc8b1d..ffdc1060 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1034,16 +1034,18 @@ static void ShowDemoWindowWidgets() ImGui::Text("Color button with Custom Picker Popup:"); - // Generate a dummy palette - static bool saved_palette_inited = false; - static ImVec4 saved_palette[32]; - if (!saved_palette_inited) + // Generate a dummy default palette. The palette will persist and can be edited. + static bool saved_palette_init = true; + static ImVec4 saved_palette[32] = { }; + if (saved_palette_init) + { for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) { ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); saved_palette[n].w = 1.0f; // Alpha } - saved_palette_inited = true; + saved_palette_init = false; + } static ImVec4 backup_color; bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); @@ -1056,12 +1058,12 @@ static void ShowDemoWindowWidgets() } if (ImGui::BeginPopup("mypicker")) { - // FIXME: Adding a drag and drop example here would be perfect! ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); ImGui::Separator(); ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::SameLine(); - ImGui::BeginGroup(); + + ImGui::BeginGroup(); // Lock X position ImGui::Text("Current"); ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)); ImGui::Text("Previous"); @@ -1077,6 +1079,8 @@ static void ShowDemoWindowWidgets() if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20))) color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + // Allow user to drop colors into each palette entry + // (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop) if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) diff --git a/imgui_internal.h b/imgui_internal.h index 92b3b96d..51953389 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1475,7 +1475,7 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); -extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, int flags); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags #else #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 60aebb2a..886c29b1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -577,6 +577,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) // CloseCurrentPopup(); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); return pressed; } @@ -1929,6 +1930,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); return value_changed; } @@ -2368,6 +2370,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); return value_changed; } @@ -3791,6 +3794,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (value_changed) MarkItemEdited(id); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) return enter_pressed; else From 158995f271d066e125aa622a4b15a28404f88d12 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Jan 2019 13:15:14 +0100 Subject: [PATCH 185/195] InputText: Fixed a bug where ESCAPE would not restore the initial value in all situations. (#2321) [@relick] --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 61b84a58..7da1a5e7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,7 @@ HOW TO UPDATE? Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] +- InputText: Fixed a bug where ESCAPE would not restore the initial value in all situations. (#2321) [@relick] - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 886c29b1..2d6a1465 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3588,7 +3588,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 } // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. - ImStrncpy(buf, edit_state.TempBuffer.Data, ImMin(apply_new_text_length + 1, buf_size)); + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); value_changed = true; } From fb4f1ff7f6dc55ea29b4cc7d391c1076f690165e Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Jan 2019 15:16:09 +0100 Subject: [PATCH 186/195] InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 4 +++- imgui_internal.h | 4 +++- imgui_widgets.cpp | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7da1a5e7..1df96435 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,6 +36,7 @@ HOW TO UPDATE? Other Changes: - Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba] - InputText: Fixed a bug where ESCAPE would not restore the initial value in all situations. (#2321) [@relick] +- InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. diff --git a/imgui.cpp b/imgui.cpp index 320b6644..2e26ddcb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2644,6 +2644,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) } g.ActiveId = id; g.ActiveIdAllowNavDirFlags = 0; + g.ActiveIdBlockNavInputFlags = 0; g.ActiveIdAllowOverlap = false; g.ActiveIdWindow = window; if (id) @@ -7630,7 +7631,8 @@ static void ImGui::NavUpdate() { if (g.ActiveId != 0) { - ClearActiveID(); + if (!(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_Cancel))) + ClearActiveID(); } else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) { diff --git a/imgui_internal.h b/imgui_internal.h index 51953389..141c05ca 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -777,6 +777,7 @@ struct ImGuiContext bool ActiveIdPreviousFrameIsAlive; bool ActiveIdPreviousFrameHasBeenEdited; int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) + int ActiveIdBlockNavInputFlags; ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; ImGuiWindow* ActiveIdPreviousFrameWindow; @@ -931,7 +932,8 @@ struct ImGuiContext ActiveIdHasBeenEdited = false; ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameHasBeenEdited = false; - ActiveIdAllowNavDirFlags = 0; + ActiveIdAllowNavDirFlags = 0x00; + ActiveIdBlockNavInputFlags = 0x00; ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; ActiveIdSource = ImGuiInputSource_None; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d6a1465..496b9cb0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2628,6 +2628,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c SetActiveID(g.ScalarAsInputTextId, window); SetHoveredID(0); g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel); char fmt_buf[32]; char data_buf[32]; @@ -3257,8 +3258,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); + g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel); if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) - g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); + g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); } else if (io.MouseClicked[0]) { From 1fb57c97c68420d531812ca71e5f14a7f246510a Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Jan 2019 15:41:20 +0100 Subject: [PATCH 187/195] Internals: InputScalarAsWidgetReplacement: Fixed seemingly unnecessary calling of SetActiveID/SetHoveredID every frame, which in turns allow us to remove the g.ActiveIdAllow/Block settings duplicated. --- imgui_widgets.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 496b9cb0..feeb3f9e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2617,18 +2617,15 @@ int ImParseFormatPrecision(const char* fmt, int default_precision) } // Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets) -// FIXME: Logic is awkward and confusing. This should be reworked to facilitate using in other situations. +// FIXME: Facilitate using this in variety of other situations. bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) { ImGuiContext& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) - // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id - SetActiveID(g.ScalarAsInputTextId, window); - SetHoveredID(0); - g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel); + // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id. + // We clear ActiveID on the first frame to allow the InputText() taking it back. + if (g.ScalarAsInputTextId == 0) + ClearActiveID(); char fmt_buf[32]; char data_buf[32]; @@ -2637,11 +2634,11 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c ImStrTrimBlanks(data_buf); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); - if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget + if (g.ScalarAsInputTextId == 0) { - IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID + // First frame we started displaying the InputText widget, we expect it to take the active id. + IM_ASSERT(g.ActiveId == id); g.ScalarAsInputTextId = g.ActiveId; - SetHoveredID(id); } if (value_changed) return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.Data, data_type, data_ptr, NULL); From 8563ef3ce4de14745d75c7c2a9443e77f23f69c3 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Jan 2019 21:13:07 +0100 Subject: [PATCH 188/195] Viewport: Popups by default merge into parent/host viewport as they have no decoration (same as menu/child). (#1542) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index cbd9a3a1..83470b3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7754,7 +7754,7 @@ static bool ImGui::GetWindowAlwaysWantOwnViewport(ImGuiWindow* window) ImGuiContext& g = *GImGui; if (g.IO.ConfigViewportsNoAutoMerge && (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) if (!window->DockIsActive) - if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip)) == 0) + if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) == 0) return true; return false; } From e1143377c2621184551d1dcac136e7e4a76e409b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Jan 2019 21:21:59 +0100 Subject: [PATCH 189/195] Viewport: Added ImGuiViewportFlags_NoFocusOnClick + support in imgui_impl_win32. Made windows with no decoration always set the _NoFocus flags. (#1542, #2117) Fix e.g. clicking on protruding combo box stealing highlight from parent window with decoration. --- examples/example_win32_directx11/main.cpp | 4 ++++ examples/imgui_impl_win32.cpp | 4 ++++ imgui.cpp | 2 ++ imgui.h | 7 ++++--- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index d0a8ae10..a8156cac 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -139,6 +139,10 @@ int main(int, char**) //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge; io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: THIS CURRENTLY DOESN'T WORK AS EXPECTED. DON'T USE IN USER APP! io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // FIXME-DPI + //io.ConfigViewportsNoAutoMerge = true; + //io.ConfigViewportsNoTaskBarIcon = false; + //io.ConfigDockingTabBarOnSingleWindows = true; + //io.ConfigDockingTransparentPayload = true; // Setup Dear ImGui style ImGui::StyleColorsDark(); diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index dc55c8e2..7b60dd1b 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -737,6 +737,10 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, case WM_SIZE: viewport->PlatformRequestResize = true; break; + case WM_MOUSEACTIVATE: + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick) + return MA_NOACTIVATE; + break; case WM_NCHITTEST: // Let mouse pass-through the window. This will allow the back-end to set io.MouseHoveredViewport properly (which is OPTIONAL). // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. diff --git a/imgui.cpp b/imgui.cpp index 83470b3e..9d84c7ee 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5520,6 +5520,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon; if (g.IO.ConfigViewportsNoDecoration || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0) viewport_flags |= ImGuiViewportFlags_NoDecoration; + if ((viewport_flags & ImGuiViewportFlags_NoDecoration) && (viewport_flags & ImGuiViewportFlags_NoTaskBarIcon)) + viewport_flags |= ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoFocusOnClick; // We can overwrite viewport flags using ImGuiWindowClass (advanced users) // We don't default to the main viewport because. diff --git a/imgui.h b/imgui.h index 00f8cd5b..212c16b3 100644 --- a/imgui.h +++ b/imgui.h @@ -2298,9 +2298,10 @@ enum ImGuiViewportFlags_ ImGuiViewportFlags_NoDecoration = 1 << 0, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips) ImGuiViewportFlags_NoTaskBarIcon = 1 << 1, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set) ImGuiViewportFlags_NoFocusOnAppearing = 1 << 2, // Platform Window: Don't take focus when created. - ImGuiViewportFlags_NoInputs = 1 << 3, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. - ImGuiViewportFlags_NoRendererClear = 1 << 4, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely). - ImGuiViewportFlags_TopMost = 1 << 5 // Platform Window: Display on top (for tooltips only) + ImGuiViewportFlags_NoFocusOnClick = 1 << 3, // Platform Window: Don't take focus when clicked on. + ImGuiViewportFlags_NoInputs = 1 << 4, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. + ImGuiViewportFlags_NoRendererClear = 1 << 5, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely). + ImGuiViewportFlags_TopMost = 1 << 6 // Platform Window: Display on top (for tooltips only) }; // The viewports created and managed by imgui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport. From 16c0a0217c46d6187b713858f3010c6ffd9fdeb6 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 31 Jan 2019 13:42:53 +0100 Subject: [PATCH 190/195] Updating supporter list. --- docs/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index cfeef09c..a6c4b416 100644 --- a/docs/README.md +++ b/docs/README.md @@ -294,21 +294,21 @@ Individuals/hobbyists: support continued maintenance and development via PayPal: Businesses: support continued maintenance and development via support contracts or sponsoring:
  _E-mail: omarcornut at gmail dot com_ -Ongoing dear imgui development is financially supported by users and private sponsors (past and present): +Ongoing dear imgui development is financially supported by users and private sponsors, recently: **Platinum-chocolate sponsors** - **Blizzard Entertainment**. **Double-chocolate sponsors** -- Media Molecule, Mobigame, Insomniac Games, Aras Pranckevičius, Lizardcube, Greggman, DotEmu, Nadeo, Supercell, Runner, Aiden Koss, Kylotonn. +- Media Molecule, Mobigame, Aras Pranckevičius, Greggman, DotEmu, Nadeo, Supercell, Runner, Aiden Koss, Kylotonn. **Salty caramel supporters** -- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Recognition Robotics, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko, Mercury Labs, Singularity Demo Group, Mischa Alff, Sebastien Ronsse, Lionel Landwerlin, Nikolay Ivanov, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts, Rainway inc. +- Recognition Robotics, ikrima, Geoffrey Evans, Mercury Labs, Singularity Demo Group, Lionel Landwerlin, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts, Rainway inc, Ondra Voves, Mesh Consultants. **Caramel supporters** -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, Kit framework, Josh Faust, Martin Donlon, Quinton, Felix, Andrew Belt, Codecat, Cort Stratton, Claudio Canepa, Doug McNabb, Emmanuel Julien, Guillaume Chereau, Jeffrey Slutter, Jeremiah Deckard, r-lyeh, Roger Clark, Nekith, Joshua Fisher, Malte Hoffmann, Mustafa Karaalioglu, Merlyn Morgan-Graham, Per Vognsen, Fabian Giesen, Jan Staubach, Matt Hargett, John Shearer, Jesse Chounard, kingcoopa, Miloš Tošić, Jonas Bernemann, Johan Andersson, Nathan Hartman, Michael Labbe, Tomasz Golebiowski, Louis Schnellbach, Felipe Alfonso, Jimmy Andrews, Bojan Endrovski, Robin Berg Pettersen, Rachel Crawford, Edsel Malasig, Andrew Johnson, Sean Hunter, Jordan Mellow, Nefarius Software Solutions, Laura Wieme, Robert Nix, Mick Honey, Astrofra, Jonas Lehmann, Steven Kah Hien Wong, Bartosz Bielecki, Oscar Penas, A M, Liam Moynihan, Artometa, Mark Lee, Dimitri Diakopoulos. +- Jerome Lanquetot, Daniel Collin, Ctrl Alt Ninja, Neil Henning, Neil Blakey-Milner, Aleksei, NeiloGD, Eric, Game Atelier, Vincent Hamm, Colin Riley, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, Josh Faust, Martin Donlon, Codecat, Doug McNabb, Emmanuel Julien, Guillaume Chereau, Jeffrey Slutter, Jeremiah Deckard, r-lyeh, Nekith, Joshua Fisher, Malte Hoffmann, Mustafa Karaalioglu, Merlyn Morgan-Graham, Per Vognsen, Fabian Giesen, Jan Staubach, Matt Hargett, John Shearer, Jesse Chounard, kingcoopa, Jonas Bernemann, Johan Andersson, Michael Labbe, Tomasz Golebiowski, Louis Schnellbach, Jimmy Andrews, Bojan Endrovski, Robin Berg Pettersen, Rachel Crawford, Andrew Johnson, Sean Hunter, Jordan Mellow, Nefarius Software Solutions, Laura Wieme, Robert Nix, Mick Honey, Steven Kah Hien Wong, Bartosz Bielecki, Oscar Penas, A M, Liam Moynihan, Artometa, Mark Lee, Dimitri Diakopoulos, Pete Goodwin. -And all other supporters; THANK YOU! +And all other past and present supporters; THANK YOU! (Please contact me if you would like to be added or removed from this list) Credits From 2d363fa315e97e3b4b1a5e1a800d0fbd6378e2c1 Mon Sep 17 00:00:00 2001 From: Michael Savage Date: Thu, 31 Jan 2019 15:19:15 +0200 Subject: [PATCH 191/195] Fixed doc typo (#2326) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index c12f9739..dd859441 100644 --- a/imgui.h +++ b/imgui.h @@ -2079,7 +2079,7 @@ struct ImFont { // Members: Hot ~62/78 bytes float FontSize; // // Height of characters, set during loading (don't change after loading) - float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() + float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImVec2 DisplayOffset; // = (0.f,0.f) // Offset font rendering by xx pixels ImVector Glyphs; // // All glyphs. ImVector IndexAdvanceX; // // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). From 578e15f006ef87ce6e5c28173146bb12f993cd42 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 31 Jan 2019 14:55:00 +0100 Subject: [PATCH 192/195] Docking: Removed unnecessary ImGuiTabItemFlags_DockedWindow internal flag. --- imgui.cpp | 2 +- imgui_internal.h | 3 +-- imgui_widgets.cpp | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9d84c7ee..ebef15a1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11474,7 +11474,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w continue; if (window->LastFrameActive + 1 >= g.FrameCount || !node_was_active) { - ImGuiTabItemFlags tab_item_flags = ImGuiTabItemFlags_DockedWindow; + ImGuiTabItemFlags tab_item_flags = 0; if (window->Flags & ImGuiWindowFlags_UnsavedDocument) tab_item_flags |= ImGuiTabItemFlags_UnsavedDocument; if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) diff --git a/imgui_internal.h b/imgui_internal.h index 6ee34b71..872d20ea 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1397,8 +1397,7 @@ enum ImGuiTabBarFlagsPrivate_ enum ImGuiTabItemFlagsPrivate_ { - ImGuiTabItemFlags_DockedWindow = 1 << 20, // [Docking] - ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. + ImGuiTabItemFlags_Unsorted = 1 << 20, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2b45e8dc..7590875a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6507,7 +6507,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, { // Drag and drop: re-order tabs float drag_distance_from_edge_x = 0.0f; - if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (flags & ImGuiTabItemFlags_DockedWindow))) + if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL))) { // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) @@ -6525,7 +6525,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } // Extract a Dockable window out of it's tab bar - if (flags & ImGuiTabItemFlags_DockedWindow) + if (docked_window != NULL) { // We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id); From 5536edede93dae8855e595f118d801a92680d9e2 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 31 Jan 2019 14:59:45 +0100 Subject: [PATCH 193/195] Docking: Fixed faulty undocking of windows with the _NoMove flag. (#2325, #2109) Whereas BeginAsDockableDragDropTarget could be reworked to filter, we simply set g.HoveredWindowUnderMovingWindow to be NULL when MovingWindow is not set, which was the initial intent. Also fixed some comments and removed unused braces in TabItemEx(). --- imgui.cpp | 10 +++++----- imgui_internal.h | 2 +- imgui_widgets.cpp | 30 ++++++++++++++---------------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ebef15a1..e82eefc9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3638,11 +3638,11 @@ void ImGui::NewFrame() g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; // Undocking - // (needs to be before UpdateMouseMovingWindow so the window is already offset and following the mouse on the detaching frame) + // (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame) DockContextNewFrameUpdateUndocking(&g); // Find hovered window - // (needs to be before UpdateMouseMovingWindow() so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) + // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) UpdateHoveredWindowAndCaptureFlags(); // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) @@ -4284,7 +4284,7 @@ static void FindHoveredWindow() g.HoveredWindow = hovered_window; g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; - g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; + g.HoveredWindowUnderMovingWindow = g.MovingWindow ? hovered_window_ignoring_moving_window : NULL; if (g.MovingWindow) g.MovingWindow->Viewport = moving_window_viewport; @@ -7434,7 +7434,7 @@ void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under) // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely. // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing. // The current code will set focus to the parent of the popup window which is incorrect. - // It rarely manifested until now because UpdateMouseMovingWindow() would call FocusWindow() again on the clicked window, + // It rarely manifested until now because UpdateMouseMovingWindowNewFrame() would call FocusWindow() again on the clicked window, // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again. // However if the clicked window has the _NoMove flag set we would be left with B focused. // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway, @@ -10304,7 +10304,7 @@ void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx) dc->WantFullRebuild = false; } - // Process Undocking requests (we need to process them _before_ the UpdateMouseMovingWindow call in NewFrame) + // Process Undocking requests (we need to process them _before_ the UpdateMouseMovingWindowNewFrame call in NewFrame) for (int n = 0; n < dc->Requests.Size; n++) { ImGuiDockRequest* req = &dc->Requests[n]; diff --git a/imgui_internal.h b/imgui_internal.h index 872d20ea..8f91bfc7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -901,7 +901,7 @@ struct ImGuiContext ImGuiWindow* CurrentWindow; // Being drawn into ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) - ImGuiWindow* HoveredWindowUnderMovingWindow; + ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. ImGuiID HoveredId; // Hovered widget bool HoveredIdAllowOverlap; ImGuiID HoveredIdPreviousFrame; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7590875a..53bbbd0b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6525,27 +6525,25 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } // Extract a Dockable window out of it's tab bar - if (docked_window != NULL) + if (docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove)) { // We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id); - if (!undocking_tab) + + if (!undocking_tab) //&& (!g.IO.ConfigDockingWithShift || g.IO.KeyShift) { - //if (!g.IO.ConfigDockingWithShift || g.IO.KeyShift) - { - float threshold_base = g.FontSize; - //float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize; - float threshold_x = (threshold_base * 2.2f); - float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f); - //GetOverlayDrawList(window)->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG] - - float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y); - if (distance_from_edge_y >= threshold_y) + float threshold_base = g.FontSize; + //float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize; + float threshold_x = (threshold_base * 2.2f); + float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f); + //GetOverlayDrawList(window)->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG] + + float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y); + if (distance_from_edge_y >= threshold_y) + undocking_tab = true; + else if (drag_distance_from_edge_x > threshold_x) + if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1)) undocking_tab = true; - else if (drag_distance_from_edge_x > threshold_x) - if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1)) - undocking_tab = true; - } } if (undocking_tab) From dc8ff68871ce0da856a533c9dd06826530df821f Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 31 Jan 2019 15:22:40 +0100 Subject: [PATCH 194/195] Docking: VisibleWindow of a node spread its _NoMove attribute to the node (fixed dragging or undocking of dock node host from collapse button). (#2325, #2109) --- imgui.cpp | 13 +++++++++++-- imgui_widgets.cpp | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e82eefc9..b4689e46 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3172,7 +3172,14 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) SetActiveID(window->MoveId, window); g.NavDisableHighlight = true; g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; - if (!(window->Flags & ImGuiWindowFlags_NoMove) && !(window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) + + bool can_move_window = true; + if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (ImGuiDockNode* node = window->DockNodeAsHost) + if (node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (can_move_window) g.MovingWindow = window; } @@ -11064,7 +11071,7 @@ static void ImGui::DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWind IM_ASSERT(node->WantMouseMove == true); ImVec2 backup_active_click_offset = g.ActiveIdClickOffset; StartMouseMovingWindow(window); - g.MovingWindow = window; // If we are docked into a non moveable root widnow, StartMouseMovingWindow() won't set g.MovingWindow. OVerride that decision. + g.MovingWindow = window; // If we are docked into a non moveable root window, StartMouseMovingWindow() won't set g.MovingWindow. Override that decision. node->WantMouseMove = false; g.ActiveIdClickOffset = backup_active_click_offset; } @@ -11533,6 +11540,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w if (IsMouseClicked(0)) { focus_tab_id = tab_bar->SelectedTabId; + + // Forward moving request to selected window if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, focus_tab_id)) StartMouseMovingWindow(tab->Window); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 53bbbd0b..395d4dad 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -712,7 +712,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no if (IsItemActive() && IsMouseDragging(0)) { bool can_extract_dock_node = false; - if (dock_node != NULL) + if (dock_node != NULL && dock_node->VisibleWindow && !(dock_node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove)) { ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); if (root_node->OnlyNodeWithWindows != dock_node || (root_node->CentralNode != NULL)) From 1f2bdd37b3d78046d875f74349f203170c5b34a1 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 31 Jan 2019 17:01:07 +0100 Subject: [PATCH 195/195] Docking: Builder: Added DockBuilderSetNodePos, DockBuilderSetNodeSize, allow DockBuilderAddNode creating floating node (dockspace requires ImGuiDockNodeFlags_Dockspace) (#2109) --- imgui.cpp | 109 ++++++++++++++++++++++++++++++++++++----------- imgui_internal.h | 16 +++++-- 2 files changed, 96 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b4689e46..aa4d6485 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10367,7 +10367,6 @@ static ImGuiDockNode* ImGui::DockContextAddNode(ImGuiContext* ctx, ImGuiID id) else IM_ASSERT(DockContextFindNodeByID(ctx, id) == NULL); ImGuiDockNode* node = IM_NEW(ImGuiDockNode)(id); - node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = true; ctx->DockContext->Nodes.SetVoidPtr(node->ID, node); return node; } @@ -10719,9 +10718,9 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1; node->ParentNode->ChildNodes[index_in_parent] = NULL; DockNodeTreeMerge(ctx, node->ParentNode, node->ParentNode->ChildNodes[index_in_parent ^ 1]); - node->ParentNode->InitFromFirstWindowViewport = true; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport + node->ParentNode->AutorityForViewport = ImGuiDataAutority_Window; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport node->ParentNode = NULL; - node->InitFromFirstWindowPosSize = true; + node->AutorityForPos = node->AutorityForSize = ImGuiDataAutority_Window; node->WantMouseMove = true; } MarkIniSettingsDirty(); @@ -10745,7 +10744,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) LastFocusedNodeID = 0; SelectedTabID = 0; WantCloseTabID = 0; - InitFromFirstWindowPosSize = InitFromFirstWindowViewport = false; + AutorityForPos = AutorityForSize = AutorityForViewport = ImGuiDataAutority_Auto; IsVisible = true; IsFocused = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false; WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false; @@ -10796,7 +10795,14 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b // When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage. // In particular it is important we init the viewport from the first window so we don't create two viewports and drop one. if (node->HostWindow == NULL && !node->IsDockSpace() && node->IsRootNode()) - node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = true; + { + if (node->AutorityForPos == ImGuiDataAutority_Auto) + node->AutorityForPos = ImGuiDataAutority_Window; + if (node->AutorityForSize == ImGuiDataAutority_Auto) + node->AutorityForSize = ImGuiDataAutority_Window; + if (node->AutorityForViewport == ImGuiDataAutority_Auto) + node->AutorityForViewport = ImGuiDataAutority_Window; + } // Add to tab bar if requested if (add_to_tab_bar) @@ -11138,7 +11144,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) } DockNodeHideHostWindow(node); - node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = false; + node->AutorityForPos = node->AutorityForSize = node->AutorityForViewport = ImGuiDataAutority_Auto; node->WantCloseAll = false; node->WantCloseTabID = 0; node->HasCloseButton = node->HasCollapseButton = false; @@ -11174,20 +11180,28 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (node->IsRootNode() && node->IsVisible) { - if (node->InitFromFirstWindowPosSize && node->Windows.Size > 0) - { - ImGuiWindow* init_window = node->Windows[0]; - SetNextWindowPos(init_window->Pos); - SetNextWindowSize(init_window->SizeFull); - SetNextWindowCollapsed(init_window->Collapsed); - } - else if (node->HostWindow == NULL) - { + ImGuiWindow* ref_window = (node->Windows.Size > 0) ? node->Windows[0] : NULL; + + // Sync Pos + if (node->AutorityForPos == ImGuiDataAutority_Window && ref_window) + SetNextWindowPos(ref_window->Pos); + else if (node->AutorityForPos == ImGuiDataAutority_DockNode) SetNextWindowPos(node->Pos); + + // Sync Size + if (node->AutorityForSize == ImGuiDataAutority_Window && ref_window) + SetNextWindowSize(ref_window->SizeFull); + else if (node->AutorityForSize == ImGuiDataAutority_DockNode) SetNextWindowSize(node->Size); - } - if (node->InitFromFirstWindowViewport && node->Windows.Size > 0) - SetNextWindowViewport(node->Windows[0]->ViewportId); + + // Sync Collapsed + if (node->AutorityForSize == ImGuiDataAutority_Window && ref_window) + SetNextWindowCollapsed(ref_window->Collapsed); + + // Sync Viewport + if (node->AutorityForViewport == ImGuiDataAutority_Window && ref_window) + SetNextWindowViewport(ref_window->ViewportId); + SetNextWindowClass(&node->WindowClass); // Begin into the host window @@ -11222,7 +11236,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) { node->HostWindow = host_window = node->ParentNode->HostWindow; } - node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = false; + node->AutorityForPos = node->AutorityForSize = node->AutorityForViewport = ImGuiDataAutority_Auto; if (node->WantMouseMove && node->HostWindow) DockNodeStartMouseMovingWindow(node, node->HostWindow); } @@ -11950,7 +11964,7 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG DockSettingsRenameNodeReferences(child_1->ID, parent_node->ID); } DockNodeApplyPosSizeToWindows(parent_node); - parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false; + parent_node->AutorityForPos = parent_node->AutorityForSize = parent_node->AutorityForViewport = ImGuiDataAutority_Auto; parent_node->VisibleWindow = merge_lead_child->VisibleWindow; parent_node->IsCentralNode = (child_0 && child_0->IsCentralNode) || (child_1 && child_1->IsCentralNode); parent_node->IsHiddenTabBar = merge_lead_child->IsHiddenTabBar; @@ -12359,11 +12373,13 @@ ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id) { + // We don't preserve relative order of multiple docked windows (by clearing DockOrder back to -1) ImGuiID window_id = ImHashStr(window_name, 0); if (ImGuiWindow* window = FindWindowByID(window_id)) { // Apply to created window SetWindowDock(window, node_id, ImGuiCond_Always); + window->DockOrder = -1; } else { @@ -12372,6 +12388,7 @@ void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id) if (settings == NULL) settings = CreateNewWindowSettings(window_name); settings->DockId = node_id; + settings->DockOrder = -1; } } @@ -12381,13 +12398,47 @@ ImGuiDockNode* ImGui::DockBuilderGetNode(ImGuiID node_id) return DockContextFindNodeByID(ctx, node_id); } -void ImGui::DockBuilderAddNode(ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags) +void ImGui::DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos) { ImGuiContext* ctx = GImGui; - DockSpace(id, ImVec2(0,0), flags | ImGuiDockNodeFlags_KeepAliveOnly); - ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); - node->SizeRef = node->Size = ref_size; - node->LastFrameAlive = -1; + ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id); + if (node == NULL) + return; + node->Pos = pos; + node->AutorityForPos = ImGuiDataAutority_DockNode; +} + +void ImGui::DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id); + if (node == NULL) + return; + node->Size = node->SizeRef = size; + node->AutorityForSize = ImGuiDataAutority_DockNode; +} + +// If you create a regular node, both ref_pos/ref_size will position the window. +// If you create a dockspace node: ref_pos won't be used, ref_size is useful on the first frame to... +ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* node = NULL; + if (flags & ImGuiDockNodeFlags_Dockspace) + { + DockSpace(id, ImVec2(0, 0), flags | ImGuiDockNodeFlags_KeepAliveOnly); + node = DockContextFindNodeByID(ctx, id); + node->LastFrameAlive = -1; + } + else + { + if (id != 0) + node = DockContextFindNodeByID(ctx, id); + if (!node) + node = DockContextAddNode(ctx, id); + node->LastFrameAlive = ctx->FrameCount; + } + return node->ID; } void ImGui::DockBuilderRemoveNode(ImGuiID node_id) @@ -12413,6 +12464,9 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id) return; bool has_document_root = false; + ImGuiDataAutority backup_root_node_autority_for_pos = root_node ? root_node->AutorityForPos : ImGuiDataAutority_Auto; + ImGuiDataAutority backup_root_node_autority_for_size = root_node ? root_node->AutorityForSize : ImGuiDataAutority_Auto; + // Process active windows ImVector nodes_to_remove; for (int n = 0; n < dc->Nodes.Data.Size; n++) @@ -12434,7 +12488,10 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id) // DockNodeMoveWindows->DockNodeAddWindow will normally set those when reaching two windows (which is only adequate during interactive merge) // Make sure we don't lose our current pos/size. (FIXME-DOCK: Consider tidying up that code in DockNodeAddWindow instead) if (root_node) - root_node->InitFromFirstWindowPosSize = false; + { + root_node->AutorityForPos = backup_root_node_autority_for_pos; + root_node->AutorityForSize = backup_root_node_autority_for_size; + } // Apply to settings for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++) diff --git a/imgui_internal.h b/imgui_internal.h index 8f91bfc7..60e732fd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -818,6 +818,13 @@ enum ImGuiDockNodeFlagsPrivate_ ImGuiDockNodeFlags_Dockspace = 1 << 10 }; +enum ImGuiDataAutority +{ + ImGuiDataAutority_Auto, + ImGuiDataAutority_DockNode, + ImGuiDataAutority_Window +}; + // sizeof() 116~160 struct ImGuiDockNode { @@ -843,8 +850,9 @@ struct ImGuiDockNode ImGuiID LastFocusedNodeID; // [Root node only] Which of our child docking node (any ancestor in the hierarchy) was last focused. ImGuiID SelectedTabID; // [Tab node only] Which of our tab is selected. ImGuiID WantCloseTabID; // [Tab node only] Set when closing a specific tab. - bool InitFromFirstWindowPosSize :1; - bool InitFromFirstWindowViewport :1; + ImGuiDataAutority AutorityForPos :3; + ImGuiDataAutority AutorityForSize :3; + ImGuiDataAutority AutorityForViewport :3; bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) bool IsFocused :1; bool IsCentralNode :1; @@ -1577,10 +1585,12 @@ namespace ImGui IMGUI_API void DockBuilderDockWindow(const char* window_name, ImGuiID node_id); IMGUI_API ImGuiDockNode*DockBuilderGetNode(ImGuiID node_id); // Warning: DO NOT HOLD ON ImGuiDockNode* pointer, will be invalided by any split/merge/remove operation. inline ImGuiDockNode* DockBuilderGetCentralNode(ImGuiID node_id) { ImGuiDockNode* node = DockBuilderGetNode(node_id); if (!node) return NULL; return DockNodeGetRootNode(node)->CentralNode; } - IMGUI_API void DockBuilderAddNode(ImGuiID node_id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0); + IMGUI_API ImGuiID DockBuilderAddNode(ImGuiID node_id, ImGuiDockNodeFlags flags = 0); IMGUI_API void DockBuilderRemoveNode(ImGuiID node_id); // Remove node and all its child, undock all windows IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiID node_id, bool clear_persistent_docking_references = true); IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the root. + IMGUI_API void DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos); + IMGUI_API void DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size); IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_dir, ImGuiID* out_id_other); IMGUI_API void DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector* in_window_remap_pairs); IMGUI_API void DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector* out_node_remap_pairs);