diff --git a/3rdparty/ocornut-imgui/imgui.cpp b/3rdparty/ocornut-imgui/imgui.cpp index 3872f45a1..170ee138b 100644 --- a/3rdparty/ocornut-imgui/imgui.cpp +++ b/3rdparty/ocornut-imgui/imgui.cpp @@ -2,7 +2,7 @@ // Main code & documentation // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. -// Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. +// Newcomers, read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui // Releases change-log at https://github.com/ocornut/imgui/releases // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. @@ -76,18 +76,20 @@ - read the FAQ below this section! - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. - call and read ImGui::ShowTestWindow() for demo code demonstrating most features. - - see examples/ folder for standalone sample applications. e.g. examples/opengl_example/ + - see examples/ folder for standalone sample applications. Prefer reading examples/opengl_example/ first at it is the simplest. - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). - getting started: - - initialisation: call ImGui::GetIO() to retrieve the ImGuiIO structure and fill the 'Settings' data. + - init: call ImGui::GetIO() to retrieve the ImGuiIO structure and fill the fields marked 'Settings'. + - init: call io.Fonts->GetTexDataAsRGBA32(...) and load the font texture pixels into graphics memory. - every frame: - 1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the 'Input' data, then call ImGui::NewFrame(). - 2/ use any ImGui function you want between NewFrame() and Render() - 3/ ImGui::Render() to render all the accumulated command-lists. it will call your RenderDrawListFn handler that you set in the IO structure. + 1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the fields marked 'Input' + 2/ call ImGui::NewFrame(). + 3/ use any ImGui function you want between NewFrame() and Render() + 4/ call ImGui::Render() to render all the accumulated command-lists. it will call your RenderDrawListFn handler that you set in the IO structure. - all rendering information are stored into command-lists until ImGui::Render() is called. - ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you must provide. - - effectively it means you can create widgets at any time in your code, regardless of "update" vs "render" considerations. + - effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases. - refer to the examples applications in the examples/ folder for instruction on how to setup your code. - a typical application skeleton may be: @@ -100,32 +102,34 @@ // TODO: Fill others settings of the io structure // Load texture atlas + // There is a default font so you don't need to care about choosing a font yet unsigned char* pixels; - int width, height, bytes_per_pixels; - io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height, &bytes_per_pixels); - // TODO: copy texture to graphics memory. - // TODO: store your texture pointer/identifier in 'io.Fonts->TexID' + int width, height; + io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height); + // TODO: At this points you've got a texture pointed to by 'pixels' and you need to upload that your your graphic system + // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID' // Application main loop while (true) { - // 1) get low-level input - // e.g. on Win32, GetKeyboardState(), or poll your events, etc. - - // 2) TODO: fill all fields of IO structure and call NewFrame + // 1) get low-level inputs (e.g. on Win32, GetKeyboardState(), or poll your events, etc.) + // TODO: fill all fields of IO structure and call NewFrame ImGuiIO& io = ImGui::GetIO(); io.DeltaTime = 1.0f/60.0f; io.MousePos = mouse_pos; io.MouseDown[0] = mouse_button_0; + io.MouseDown[1] = mouse_button_1; io.KeysDown[i] = ... + + // 2) call NewFrame(), after this point you can use ImGui::* functions anytime ImGui::NewFrame(); - // 3) most of your application code here - you can use any of ImGui::* functions at any point in the frame + // 3) most of your application code here ImGui::Begin("My window"); ImGui::Text("Hello, world."); ImGui::End(); - GameUpdate(); - GameRender(); + MyGameUpdate(); // may use ImGui functions + MyGameRender(); // may use ImGui functions // 4) render & swap video buffers ImGui::Render(); @@ -410,6 +414,7 @@ - window: get size/pos helpers given names (see discussion in #249) - window: a collapsed window can be stuck behind the main menu bar? - window: detect extra End() call that pop the "Debug" window out and assert at call site instead of later. + - window: consider renaming "GetWindowFont" which conflict with old Windows #define (#340) - window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic. - draw-list: 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). !- scrolling: allow immediately effective change of scroll if we haven't appended items yet @@ -439,6 +444,8 @@ - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) (#125) - columns: columns header to act as button (~sort op) and allow resize/reorder (#125) - columns: user specify columns size (#125) + - columns: flag to add horizontal separator above/below? + - columns/layout: setup minimum line height (equivalent of automatically calling AlignFirstTextHeightToWidgets) - combo: sparse combo boxes (via function call?) - combo: contents should extends to fit label if combo widget is small - combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203) @@ -475,12 +482,14 @@ - tree node / optimization: avoid formatting when clipped. - tree node: tree-node/header right-most side doesn't take account of horizontal scrolling. - tree node: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings + - tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer) - textwrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (git issue #249) - settings: write more decent code to allow saving/loading new fields - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file - style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost. - style: color-box not always square? - style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps to other settings? avoid implementing duplicate helpers such as SmallCheckbox(), etc. + - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation). - text: simple markup language for color change? - font: helper to add glyph redirect/replacements (e.g. redirect alternate apostrophe unicode code points to ascii one, etc.) - log: LogButtons() options for specifying depth and/or hiding depth slider @@ -1597,7 +1606,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) { ImGuiState& g = *GImGui; g.ActiveId = id; - g.ActiveIdAllowHoveringOthers = false; + g.ActiveIdAllowOverlap = false; g.ActiveIdIsJustActivated = true; g.ActiveIdWindow = window; } @@ -1606,7 +1615,7 @@ void ImGui::SetHoveredID(ImGuiID id) { ImGuiState& g = *GImGui; g.HoveredId = id; - g.HoveredIdAllowHoveringOthers = false; + g.HoveredIdAllowOverlap = false; } void ImGui::KeepAliveID(ImGuiID id) @@ -1667,7 +1676,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) window->DC.LastItemHoveredRect = true; window->DC.LastItemHoveredAndUsable = false; if (g.HoveredRootWindow == window->RootWindow) - if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdAllowHoveringOthers || (g.ActiveId == window->MoveID)) + if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdAllowOverlap || (g.ActiveId == window->MoveID)) if (IsWindowContentHoverable(window)) window->DC.LastItemHoveredAndUsable = true; } @@ -1696,11 +1705,11 @@ bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs) { ImGuiState& g = *GImGui; - if (g.HoveredId == 0 || g.HoveredId == id || g.HoveredIdAllowHoveringOthers) + if (g.HoveredId == 0 || g.HoveredId == id || g.HoveredIdAllowOverlap) { ImGuiWindow* window = GetCurrentWindowRead(); if (g.HoveredWindow == window || (flatten_childs && g.HoveredRootWindow == window->RootWindow)) - if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdAllowHoveringOthers) && ImGui::IsMouseHoveringRect(bb.Min, bb.Max)) + if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdAllowOverlap) && ImGui::IsMouseHoveringRect(bb.Min, bb.Max)) if (IsWindowContentHoverable(g.HoveredRootWindow)) return true; } @@ -1848,11 +1857,11 @@ void ImGui::NewFrame() ImGuiState& g = *GImGui; // Check user data - IM_ASSERT(g.IO.DeltaTime >= 0.0f); + IM_ASSERT(g.IO.DeltaTime >= 0.0f); // Need a positive DeltaTime (zero is tolerated but will cause some timing issues) IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f); IM_ASSERT(g.IO.Fonts->Fonts.Size > 0); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? - IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid style setting if (!g.Initialized) { @@ -1928,7 +1937,7 @@ void ImGui::NewFrame() // Clear reference to active widget if the widget isn't alive anymore g.HoveredIdPreviousFrame = g.HoveredId; g.HoveredId = 0; - g.HoveredIdAllowHoveringOthers = false; + g.HoveredIdAllowOverlap = false; if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) SetActiveID(0); g.ActiveIdPreviousFrame = g.ActiveId; @@ -1982,6 +1991,7 @@ void ImGui::NewFrame() g.IO.WantTextInput = (g.ActiveId != 0 && g.InputTextState.Id == g.ActiveId); g.MouseCursor = ImGuiMouseCursor_Arrow; g.CaptureMouseNextFrame = g.CaptureKeyboardNextFrame = false; + g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. if (mouse_owned_by_application) @@ -2269,8 +2279,7 @@ static void AddDrawListToRenderList(ImVector& out_render_list, ImDr // If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly. const unsigned long long int max_vtx_idx = (unsigned long long int)1L << (sizeof(ImDrawIdx)*8); (void)max_vtx_idx; - IM_ASSERT((unsigned long long int)draw_list->_VtxCurrentIdx <= max_vtx_idx); - (void)max_vtx_idx; + IM_ASSERT((unsigned long long int)draw_list->_VtxCurrentIdx <= max_vtx_idx); // Too many vertices in same ImDrawList GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size; GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size; @@ -2331,8 +2340,15 @@ void ImGui::EndFrame() ImGui::EndTooltip(); } + // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.OsImePosRequest - g.OsImePosSet) > 0.0001f) + { + g.IO.ImeSetInputScreenPosFn((int)g.OsImePosRequest.x, (int)g.OsImePosRequest.y); + g.OsImePosSet = g.OsImePosRequest; + } + // Hide implicit "Debug" window if it hasn't been used - IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin/End + IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls if (g.CurrentWindow && !g.CurrentWindow->Accessed) g.CurrentWindow->Active = false; ImGui::End(); @@ -2368,9 +2384,8 @@ void ImGui::EndFrame() for (int i = 0; i != g.Windows.Size; i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is active its parent will add it - if (window->Active) - continue; + if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it + continue; AddWindowToSortedBuffer(g.WindowsSortBuffer, window); } IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong @@ -2602,6 +2617,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end } } +// 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, ImGuiAlign align, const ImVec2* clip_min, const ImVec2* clip_max) { // Hide anything after a '##' string @@ -3011,6 +3027,16 @@ bool ImGui::IsItemVisible() return r.Overlaps(window->DC.LastItemRect); } +// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. +void ImGui::SetItemAllowOverlap() +{ + ImGuiState& g = *GImGui; + if (g.HoveredId == g.CurrentWindow->DC.LastItemID) + g.HoveredIdAllowOverlap = true; + if (g.ActiveId == g.CurrentWindow->DC.LastItemID) + g.ActiveIdAllowOverlap = true; +} + ImVec2 ImGui::GetItemRectMin() { ImGuiWindow* window = GetCurrentWindowRead(); @@ -3069,7 +3095,7 @@ void ImGui::BeginTooltip() void ImGui::EndTooltip() { - IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls ImGui::End(); } @@ -3238,7 +3264,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_opened, ImGuiWindowFlags e void ImGui::EndPopup() { ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls IM_ASSERT(GImGui->CurrentPopupStack.Size > 0); ImGui::End(); if (!(window->Flags & ImGuiWindowFlags_Modal)) @@ -3316,7 +3342,7 @@ void ImGui::EndChild() { ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); + IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss if ((window->Flags & ImGuiWindowFlags_ComboBox) || window->BeginCount > 1) { ImGui::End(); @@ -4261,7 +4287,7 @@ float ImGui::CalcItemWidth() static void SetCurrentFont(ImFont* font) { ImGuiState& g = *GImGui; - IM_ASSERT(font && font->IsLoaded()); + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; @@ -5533,6 +5559,7 @@ bool ImGui::TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags) return opened; } +// FIXME: Split into CollapsingHeader(label, default_open?) and TreeNodeBehavior(label), obsolete the 4 parameters function. bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display_frame, bool default_open) { ImGuiWindow* window = GetCurrentWindow(); @@ -5541,6 +5568,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; + const ImVec2 padding = display_frame ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); IM_ASSERT(str_id != NULL || label != NULL); if (str_id == NULL) @@ -5548,27 +5576,27 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display if (label == NULL) label = str_id; const ImGuiID id = window->GetID(str_id); - - // Framed header expand a little outside the default padding - const ImVec2 window_padding = window->WindowPadding; const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 pos_min = window->DC.CursorPos; - const ImVec2 pos_max = window->Pos + GetContentRegionMax(); - ImRect bb = ImRect(pos_min, ImVec2(pos_max.x, pos_min.y + label_size.y)); + + // We vertically grow up to current line height up the typical widget height. + const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset - padding.y); + const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), label_size.y + padding.y*2); + ImRect bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height)); if (display_frame) { - bb.Min.x -= (float)(int)(window_padding.x*0.5f) - 1; - bb.Max.x += (float)(int)(window_padding.x*0.5f) - 1; - bb.Max.y += style.FramePadding.y * 2; + // Framed header expand a little outside the default padding + bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1; + bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1; } - const float collapser_width = g.FontSize + style.FramePadding.x*2; - const ImRect text_bb(bb.Min, bb.Min + ImVec2(collapser_width + style.FramePadding.x*2*0 + (label_size.x > 0.0f ? label_size.x : 0.0f), label_size.y)); - ItemSize(ImVec2(text_bb.GetSize().x, bb.GetSize().y), display_frame ? style.FramePadding.y : 0.0f); + const float collapser_width = g.FontSize + padding.x*2; + const float text_width = collapser_width + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser + ItemSize(ImVec2(text_width, frame_height), text_base_offset_y); - const ImRect interact_bb = display_frame ? bb : ImRect(text_bb.Min, text_bb.Max + ImVec2(style.FramePadding.x*2,0.0f)); // FIXME + // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing + // (Ideally we'd want to add a flag for the user to specify we want want the hit test to be done up to the right side of the content or not) + const ImRect interact_bb = display_frame ? bb : ImRect(bb.Min.x, bb.Min.y, bb.Min.x + text_width + style.ItemSpacing.x*2, bb.Max.y); bool opened = TreeNodeBehaviorIsOpened(id, (default_open ? ImGuiTreeNodeFlags_DefaultOpen : 0) | (display_frame ? ImGuiTreeNodeFlags_NoAutoExpandOnLog : 0)); - if (!ItemAdd(interact_bb, &id)) return opened; @@ -5582,22 +5610,24 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display // Render const ImU32 col = window->Color((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + const ImVec2 text_pos = bb.Min + padding + ImVec2(collapser_width, text_base_offset_y); if (display_frame) { // Framed type RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderCollapseTriangle(bb.Min + style.FramePadding, opened, 1.0f, true); + RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), opened, 1.0f, true); if (g.LogEnabled) { // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. const char log_prefix[] = "\n##"; - LogRenderedText(bb.Min + style.FramePadding, log_prefix, log_prefix+3); - } - RenderTextClipped(bb.Min + style.FramePadding + ImVec2(collapser_width,0), bb.Max, label, NULL, &label_size); - if (g.LogEnabled) - { const char log_suffix[] = "##"; - LogRenderedText(bb.Min + style.FramePadding, log_suffix, log_suffix+2); + LogRenderedText(text_pos, log_prefix, log_prefix+3); + RenderTextClipped(text_pos, bb.Max, label, NULL, &label_size); + LogRenderedText(text_pos, log_suffix+1, log_suffix+3); + } + else + { + RenderTextClipped(text_pos, bb.Max, label, NULL, &label_size); } } else @@ -5605,10 +5635,11 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display // Unframed typed for tree nodes if (hovered) RenderFrame(bb.Min, bb.Max, col, false); - RenderCollapseTriangle(bb.Min + ImVec2(style.FramePadding.x, g.FontSize*0.15f), opened, 0.70f, false); + + RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); if (g.LogEnabled) - LogRenderedText(bb.Min, ">"); - RenderText(bb.Min + ImVec2(collapser_width,0), label); + LogRenderedText(text_pos, ">"); + RenderText(text_pos, label); } return opened; @@ -7109,7 +7140,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f } // Edit a string of text -// FIXME: This is rather complex partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. +// FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) { ImGuiWindow* window = GetCurrentWindow(); @@ -7128,7 +7159,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; - ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), is_multiline ? ImGui::GetTextLineHeight() * 8.0f : label_size.y); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size + style.FramePadding*2.0f); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); @@ -7197,7 +7228,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 { // Start edition // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) - // From the moment we focused we are ignoring the content of 'buf' + // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) const int prev_len_w = edit_state.CurLenW; edit_state.Text.resize(buf_size+1); // wchar count <= utf-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash. edit_state.InitialText.resize(buf_size+1); // utf-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash. @@ -7205,7 +7236,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const char* buf_end = NULL; edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end); edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. - edit_state.InputCursorScreenPos = ImVec2(-1.f, -1.f); edit_state.CursorAnimReset(); // Preserve cursor position and undo/redo stack if we come back to same widget @@ -7259,8 +7289,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 edit_state.BufSizeA = buf_size; // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. - // Down the line we should have a cleaner concept of focused vs active in the library. - g.ActiveIdAllowHoveringOthers = !io.MouseDown[0]; + // Down the line we should have a cleaner library-wide concept of Selected vs Active. + g.ActiveIdAllowOverlap = !io.MouseDown[0]; // Edit in progress const float mouse_x = (g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; @@ -7407,9 +7437,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else { // Apply new value immediately - copy modified buffer back - // Note that as soon as we can focus into the input box, the in-widget value gets priority over any underlying modification of the input buffer - // FIXME: We actually always render 'buf' when calling DrawList->AddText - // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks + // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. + // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. if (is_editable) { edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4); @@ -7624,11 +7654,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (cursor_is_visible) draw_window->DrawList->AddLine(cursor_screen_pos + ImVec2(0.0f,-g.FontSize+0.5f), cursor_screen_pos + ImVec2(0.0f,-1.5f), window->Color(ImGuiCol_Text)); - // Notify OS of text input position for advanced IME - if (is_editable && io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_screen_pos) > 0.0001f) - io.ImeSetInputScreenPosFn((int)cursor_screen_pos.x - 1, (int)(cursor_screen_pos.y - g.FontSize)); // -1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety. - - edit_state.InputCursorScreenPos = cursor_screen_pos; + // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) + if (is_editable) + g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); } else { @@ -8650,7 +8678,7 @@ void ImGui::EndGroup() ImGuiWindow* window = GetCurrentWindow(); ImGuiStyle& style = ImGui::GetStyle(); - IM_ASSERT(!window->DC.GroupStack.empty()); + IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls ImGuiGroupData& group_data = window->DC.GroupStack.back(); diff --git a/3rdparty/ocornut-imgui/imgui_demo.cpp b/3rdparty/ocornut-imgui/imgui_demo.cpp index dce9e28f3..35c7396a7 100644 --- a/3rdparty/ocornut-imgui/imgui_demo.cpp +++ b/3rdparty/ocornut-imgui/imgui_demo.cpp @@ -226,7 +226,7 @@ void ImGui::ShowTestWindow(bool* p_opened) { ImFont* font = atlas->Fonts[i]; ImGui::BulletText("Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); - ImGui::TreePush((void*)intptr_t(i)); + ImGui::TreePush((void*)(intptr_t)i); if (i > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { atlas->Fonts[i] = atlas->Fonts[0]; atlas->Fonts[0] = font; } } ImGui::PushFont(font); ImGui::Text("The quick brown fox jumps over the lazy dog"); @@ -264,7 +264,7 @@ void ImGui::ShowTestWindow(bool* p_opened) { for (int i = 0; i < 5; i++) { - if (ImGui::TreeNode((void*)intptr_t(i), "Child %d", i)) + if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) { ImGui::Text("blah blah"); ImGui::SameLine(); @@ -779,7 +779,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::TreePop(); } - if (ImGui::TreeNode("Widgets Alignment")) + if (ImGui::TreeNode("Widgets Width")) { static float f = 0.0f; ImGui::Text("PushItemWidth(100)"); @@ -950,6 +950,17 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Text("Widget"); ImGui::SameLine(); ImGui::SmallButton("Widget"); + // Tree + const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::Button("Button##1"); + ImGui::SameLine(0.0f, spacing); + if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + + ImGui::AlignFirstTextHeightToWidgets(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). + bool tree_opened = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); + if (tree_opened) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + ImGui::TreePop(); } @@ -969,7 +980,7 @@ void ImGui::ShowTestWindow(bool* p_opened) if (i > 0) ImGui::SameLine(); ImGui::BeginGroup(); ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom"); - ImGui::BeginChild(ImGui::GetID((void*)intptr_t(i)), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true); + ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true); if (scroll_to) ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f); for (int line = 0; line < 100; line++) @@ -1038,13 +1049,13 @@ void ImGui::ShowTestWindow(bool* p_opened) 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("offset", (float*)&offset, 0.5f, -200, 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); - ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x+size.x,pos.y+size.y), ImColor(90,90,120,255)); - ImGui::GetWindowDrawList()->AddText(ImGui::GetWindowFont(), ImGui::GetWindowFontSize()*2.0f, ImVec2(pos.x+offset.x,pos.y+offset.y), ImColor(255,255,255,255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); ImGui::InvisibleButton("##dummy", size); if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } + ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x+size.x,pos.y+size.y), ImColor(90,90,120,255)); + ImGui::GetWindowDrawList()->AddText(ImGui::GetWindowFont(), ImGui::GetWindowFontSize()*2.0f, ImVec2(pos.x+offset.x,pos.y+offset.y), ImColor(255,255,255,255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); ImGui::TreePop(); } } @@ -1328,9 +1339,9 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::TreePop(); } - bool opened = ImGui::TreeNode("Tree within single cell"); + bool node_opened = ImGui::TreeNode("Tree within single cell"); ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell.\nThere's no storage of state per-cell."); - if (opened) + if (node_opened) { ImGui::Columns(2, "tree items"); ImGui::Separator(); @@ -2191,16 +2202,15 @@ static void ShowExampleAppPropertyEditor(bool* p_opened) ImGui::Columns(2); ImGui::Separator(); - ImGui::Text("Item1"); ImGui::NextColumn(); - ImGui::Text("value1"); ImGui::NextColumn(); - struct funcs { static void ShowDummyObject(const char* prefix, ImU32 uid) { - ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. + ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. + ImGui::AlignFirstTextHeightToWidgets(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. bool opened = ImGui::TreeNode("Object", "%s_%u", prefix, uid); ImGui::NextColumn(); + ImGui::AlignFirstTextHeightToWidgets(); ImGui::Text("my sailor is rich"); ImGui::NextColumn(); if (opened) diff --git a/3rdparty/ocornut-imgui/imgui_draw.cpp b/3rdparty/ocornut-imgui/imgui_draw.cpp index 75fd09d05..fd09f8640 100644 --- a/3rdparty/ocornut-imgui/imgui_draw.cpp +++ b/3rdparty/ocornut-imgui/imgui_draw.cpp @@ -19,7 +19,7 @@ #include // vsnprintf, sscanf, printf #include // new (ptr) #if !defined(alloca) && !defined(__FreeBSD__) -#if defined(_WIN32) +#ifdef _WIN32 #include // alloca #else #include // alloca @@ -1535,25 +1535,27 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() 19,3,8,0,0,0,4,4,16,0,4,1,5,1,3,0,3,4,6,2,17,10,10,31,6,4,3,6,10,126,7,3,2,2,0,9,0,0,5,20,13,0,15,0,6,0,2,5,8,64,50,3,2,12,2,9,0,0,11,8,20, 109,2,18,23,0,0,9,61,3,0,28,41,77,27,19,17,81,5,2,14,5,83,57,252,14,154,263,14,20,8,13,6,57,39,38, }; - static int ranges_unpacked = false; - static ImWchar ranges[8 + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1] = + static ImWchar base_ranges[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions 0xFF00, 0xFFEF, // Half-width characters }; - if (!ranges_unpacked) + static bool full_ranges_unpacked = false; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1]; + if (!full_ranges_unpacked) { // Unpack int codepoint = 0x4e00; - ImWchar* dst = &ranges[8]; + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + ImWchar* dst = full_ranges + IM_ARRAYSIZE(base_ranges);; for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2) dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1)); dst[0] = 0; - ranges_unpacked = true; + full_ranges_unpacked = true; } - return &ranges[0]; + return &full_ranges[0]; } const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() diff --git a/3rdparty/ocornut-imgui/imgui_internal.h b/3rdparty/ocornut-imgui/imgui_internal.h index 84b7653eb..7a56e85fe 100644 --- a/3rdparty/ocornut-imgui/imgui_internal.h +++ b/3rdparty/ocornut-imgui/imgui_internal.h @@ -196,33 +196,33 @@ enum ImGuiDataType // NB: we can't rely on ImVec2 math operators being available here struct IMGUI_API ImRect { - ImVec2 Min; // Upper-left - ImVec2 Max; // Lower-right + ImVec2 Min; // Upper-left + ImVec2 Max; // Lower-right ImRect() : Min(FLT_MAX,FLT_MAX), Max(-FLT_MAX,-FLT_MAX) {} ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} - ImVec2 GetCenter() const { return ImVec2((Min.x+Max.x)*0.5f, (Min.y+Max.y)*0.5f); } - ImVec2 GetSize() const { return ImVec2(Max.x-Min.x, Max.y-Min.y); } - float GetWidth() const { return Max.x-Min.x; } - float GetHeight() const { return Max.y-Min.y; } - ImVec2 GetTL() const { return Min; } - ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } - ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } - ImVec2 GetBR() const { return Max; } - bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } - bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; } - bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } - void Add(const ImVec2& rhs) { if (Min.x > rhs.x) Min.x = rhs.x; if (Min.y > rhs.y) Min.y = rhs.y; if (Max.x < rhs.x) Max.x = rhs.x; if (Max.y < rhs.y) Max.y = rhs.y; } - void Add(const ImRect& rhs) { if (Min.x > rhs.Min.x) Min.x = rhs.Min.x; if (Min.y > rhs.Min.y) Min.y = rhs.Min.y; if (Max.x < rhs.Max.x) Max.x = rhs.Max.x; if (Max.y < rhs.Max.y) Max.y = rhs.Max.y; } - void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } - void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } - void Reduce(const ImVec2& amount) { Min.x += amount.x; Min.y += amount.y; Max.x -= amount.x; Max.y -= amount.y; } - void Clip(const ImRect& clip) { if (Min.x < clip.Min.x) Min.x = clip.Min.x; if (Min.y < clip.Min.y) Min.y = clip.Min.y; if (Max.x > clip.Max.x) Max.x = clip.Max.x; if (Max.y > clip.Max.y) Max.y = clip.Max.y; } - void Round() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } - ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const + ImVec2 GetCenter() const { return ImVec2((Min.x+Max.x)*0.5f, (Min.y+Max.y)*0.5f); } + ImVec2 GetSize() const { return ImVec2(Max.x-Min.x, Max.y-Min.y); } + float GetWidth() const { return Max.x-Min.x; } + float GetHeight() const { return Max.y-Min.y; } + ImVec2 GetTL() const { return Min; } // Top-left + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left + ImVec2 GetBR() const { return Max; } // Bottom-right + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& rhs) { if (Min.x > rhs.x) Min.x = rhs.x; if (Min.y > rhs.y) Min.y = rhs.y; if (Max.x < rhs.x) Max.x = rhs.x; if (Max.y < rhs.y) Max.y = rhs.y; } + void Add(const ImRect& rhs) { if (Min.x > rhs.Min.x) Min.x = rhs.Min.x; if (Min.y > rhs.Min.y) Min.y = rhs.Min.y; if (Max.x < rhs.Max.x) Max.x = rhs.Max.x; if (Max.y < rhs.Max.y) Max.y = rhs.Max.y; } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } + void Reduce(const ImVec2& amount) { Min.x += amount.x; Min.y += amount.y; Max.x -= amount.x; Max.y -= amount.y; } + void Clip(const ImRect& clip) { if (Min.x < clip.Min.x) Min.x = clip.Min.x; if (Min.y < clip.Min.y) Min.y = clip.Min.y; if (Max.x > clip.Max.x) Max.x = clip.Max.x; if (Max.y > clip.Max.y) Max.y = clip.Max.y; } + void Round() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } + ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const { if (!on_edge && Contains(p)) return p; @@ -237,8 +237,8 @@ struct IMGUI_API ImRect // Stacked color modifier, backup of modified data so we can restore it struct ImGuiColMod { - ImGuiCol Col; - ImVec4 PreviousValue; + ImGuiCol Col; + ImVec4 PreviousValue; }; // Stacked style modifier, backup of modified data so we can restore it @@ -251,34 +251,34 @@ struct ImGuiStyleMod // Stacked data for BeginGroup()/EndGroup() struct ImGuiGroupData { - ImVec2 BackupCursorPos; - ImVec2 BackupCursorMaxPos; - float BackupIndentX; - float BackupCurrentLineHeight; - float BackupCurrentLineTextBaseOffset; - float BackupLogLinePosY; - bool AdvanceCursor; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + float BackupIndentX; + float BackupCurrentLineHeight; + float BackupCurrentLineTextBaseOffset; + float BackupLogLinePosY; + bool AdvanceCursor; }; // Per column data for Columns() struct ImGuiColumnData { - float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) - //float IndentX; + float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) + //float IndentX; }; // Simple column measurement currently used for MenuItem() only. This is very short-sighted for now and NOT a generic helper. struct IMGUI_API ImGuiSimpleColumns { - int Count; - float Spacing; - float Width, NextWidth; - float Pos[8], NextWidths[8]; + int Count; + float Spacing; + float Width, NextWidth; + float Pos[8], NextWidths[8]; ImGuiSimpleColumns(); - void Update(int count, float spacing, bool clear); - float DeclColumns(float w0, float w1, float w2); - float CalcExtraSpace(float avail_w); + void Update(int count, float spacing, bool clear); + float DeclColumns(float w0, float w1, float w2); + float CalcExtraSpace(float avail_w); }; // Internal state of the currently focused/edited text input box @@ -294,7 +294,6 @@ struct IMGUI_API ImGuiTextEditState ImGuiStb::STB_TexteditState StbState; float CursorAnim; bool CursorFollow; - ImVec2 InputCursorScreenPos; // Cursor position in screen space to be used by IME callback. bool SelectedAllMouseLock; ImGuiTextEditState() { memset(this, 0, sizeof(*this)); } @@ -309,11 +308,11 @@ struct IMGUI_API ImGuiTextEditState // Data saved in imgui.ini file struct ImGuiIniData { - char* Name; - ImGuiID ID; - ImVec2 Pos; - ImVec2 Size; - bool Collapsed; + char* Name; + ImGuiID ID; + ImVec2 Pos; + ImVec2 Size; + bool Collapsed; }; // Mouse cursor data (used when io.MouseDrawCursor is set) @@ -329,11 +328,11 @@ struct ImGuiMouseCursorData // Storage for current popup stack struct ImGuiPopupRef { - ImGuiID PopupID; // Set on OpenPopup() - ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() - ImGuiWindow* ParentWindow; // Set on OpenPopup() - ImGuiID ParentMenuSet; // Set on OpenPopup() - ImVec2 MousePosOnOpen; // Copy of mouse position at the time of opening popup + ImGuiID PopupID; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* ParentWindow; // Set on OpenPopup() + ImGuiID ParentMenuSet; // Set on OpenPopup() + ImVec2 MousePosOnOpen; // Copy of mouse position at the time of opening popup ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } }; @@ -361,13 +360,13 @@ struct ImGuiState ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) ImGuiID HoveredId; // Hovered widget - bool HoveredIdAllowHoveringOthers; + bool HoveredIdAllowOverlap; ImGuiID HoveredIdPreviousFrame; ImGuiID ActiveId; // Active widget ImGuiID ActiveIdPreviousFrame; bool ActiveIdIsAlive; bool ActiveIdIsJustActivated; // Set at the time of activation for one frame - bool ActiveIdAllowHoveringOthers; // Set only by active widget + bool ActiveIdAllowOverlap; // Set only by active widget ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Pointer is only valid if ActiveID is the "#MOVE" identifier of a window. ImVector Settings; // .ini Settings @@ -414,6 +413,7 @@ struct ImGuiState ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? char Tooltip[1024]; char* PrivateClipboard; // If no custom clipboard handler is defined + ImVec2 OsImePosRequest, OsImePosSet; // Cursor position request & last passed to the OS Input Method Editor // Logging bool LogEnabled; @@ -445,13 +445,13 @@ struct ImGuiState HoveredWindow = NULL; HoveredRootWindow = NULL; HoveredId = 0; - HoveredIdAllowHoveringOthers = false; + HoveredIdAllowOverlap = false; HoveredIdPreviousFrame = 0; ActiveId = 0; ActiveIdPreviousFrame = 0; ActiveIdIsAlive = false; ActiveIdIsJustActivated = false; - ActiveIdAllowHoveringOthers = false; + ActiveIdAllowOverlap = false; ActiveIdWindow = NULL; MovedWindow = NULL; SettingsDirtyTimer = 0.0f; @@ -477,6 +477,7 @@ struct ImGuiState ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); memset(Tooltip, 0, sizeof(Tooltip)); PrivateClipboard = NULL; + OsImePosRequest = OsImePosSet = ImVec2(-1.0f, -1.0f); ModalWindowDarkeningRatio = 0.0f; OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging @@ -682,6 +683,7 @@ namespace ImGui IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); + IMGUI_API void SetItemAllowOverlap(); // Allow last item to be overlapped by a subsequent item // NB: All position are in absolute pixels coordinates (not window coordinates) IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);