From c725710c6dc2d0b9749242b9e929e9abd72c7e98 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Jun 2018 17:24:46 +0200 Subject: [PATCH 01/11] Comments --- imgui.cpp | 25 ++++++++++++------------- imgui_demo.cpp | 1 + imgui_internal.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7a4b3c672..e57cdbaa5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9739,7 +9739,6 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu TextUnformatted(label, FindRenderedTextEnd(label)); EndGroup(); PopID(); - return value_changed; } @@ -10098,9 +10097,7 @@ bool ImGui::RadioButton(const char* label, int* v, int v_button) { const bool pressed = RadioButton(label, *v == v_button); if (pressed) - { *v = v_button; - } return pressed; } @@ -10381,7 +10378,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; - if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn + 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); @@ -11090,7 +11087,6 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in TextUnformatted(label, FindRenderedTextEnd(label)); EndGroup(); - return value_changed; } @@ -11468,6 +11464,7 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags return false; } +// FIXME: Rename to BeginListBox() // Helper to calculate the size of a listbox and display a label on the right. // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty" bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) @@ -11495,6 +11492,7 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) return true; } +// FIXME: Rename to BeginListBox() bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) { // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. @@ -11511,6 +11509,7 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item return ListBoxHeader(label, size); } +// FIXME: Rename to EndListBox() void ImGui::ListBoxFooter() { ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow; @@ -11658,7 +11657,7 @@ bool ImGui::BeginMenuBar() return false; IM_ASSERT(!window->DC.MenuBarAppending); - BeginGroup(); // Save position + BeginGroup(); // Backup position on layer 0 PushID("##menubar"); // 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. @@ -11710,7 +11709,7 @@ void ImGui::EndMenuBar() PopID(); window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. window->DC.GroupStack.back().AdvanceCursor = false; - EndGroup(); + EndGroup(); // Restore position on layer 0 window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.NavLayerCurrent--; window->DC.NavLayerCurrentMask >>= 1; @@ -12792,6 +12791,7 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // 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.) void ImGui::BeginGroup() { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); @@ -12803,21 +12803,20 @@ void ImGui::BeginGroup() group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupLogLinePosY = window->DC.LogLinePosY; - group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive; + group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.AdvanceCursor = true; window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; window->DC.IndentX = window->DC.GroupOffsetX; window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.CurrentLineHeight = 0.0f; - window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; // To enforce Log carriage return } void ImGui::EndGroup() { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls ImGuiGroupData& group_data = window->DC.GroupStack.back(); @@ -12827,11 +12826,11 @@ void ImGui::EndGroup() window->DC.CursorPos = group_data.BackupCursorPos; window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); - window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; - window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; window->DC.IndentX = group_data.BackupIndentX; window->DC.GroupOffsetX = group_data.BackupGroupOffsetX; - window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; + window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; + window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; // To enforce Log carriage return if (group_data.AdvanceCursor) { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1ec1404b2..53367a080 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -328,6 +328,7 @@ void ImGui::ShowDemoWindow(bool* p_open) { // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; static int item_current = 0; ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); diff --git a/imgui_internal.h b/imgui_internal.h index eb07f0166..1ef9ce9dd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -980,7 +980,7 @@ struct IMGUI_API ImGuiWindow ImRect OuterRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. ImRect InnerMainRect, InnerClipRect; ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis - int LastFrameActive; + int LastFrameActive; // Last frame number the window was Active. float ItemWidthDefault; ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items ImGuiStorage StateStorage; From cd455a4600b351fb7da053c024101315a96638f2 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Jun 2018 18:44:33 +0200 Subject: [PATCH 02/11] Added IsItemDeactivated() to query if the last item was active previously but isn't anymore. Useful for Undo/Redo patterns. (#820, #956, #1875) --- CHANGELOG.txt | 1 + imgui.cpp | 25 +++++++++++++++++++------ imgui.h | 1 + imgui_demo.cpp | 12 +++++++++--- imgui_internal.h | 6 +++++- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e1b9c38c8..c471d45d9 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -63,6 +63,7 @@ Other Changes: - 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 but isn't anymore. Useful for Undo/Redo patterns. (#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) - TreeNode: Fixed nodes with ImGuiTreeNodeFlags_Leaf flag always returning true which was meaningless. diff --git a/imgui.cpp b/imgui.cpp index e57cdbaa5..825a63d12 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2251,6 +2251,8 @@ void ImGui::KeepAliveID(ImGuiID id) ImGuiContext& g = *GImGui; if (g.ActiveId == id) g.ActiveIdIsAlive = true; + if (g.ActiveIdPreviousFrame == id) + g.ActiveIdPreviousFrameIsAlive = true; } static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) @@ -3719,7 +3721,8 @@ void ImGui::NewFrame() g.ActiveIdTimer += g.IO.DeltaTime; g.LastActiveIdTimer += g.IO.DeltaTime; g.ActiveIdPreviousFrame = g.ActiveId; - g.ActiveIdIsAlive = false; + g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdIsAlive = g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) g.ScalarAsInputTextId = 0; @@ -3940,7 +3943,7 @@ void ImGui::Shutdown(ImGuiContext* context) g.NavWindow = NULL; g.HoveredWindow = NULL; g.HoveredRootWindow = NULL; - g.ActiveIdWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; g.MovingWindow = NULL; g.ColorModifiers.clear(); g.StyleModifiers.clear(); @@ -4978,6 +4981,13 @@ bool ImGui::IsItemActive() return false; } +bool ImGui::IsItemDeactivated() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); +} + bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; @@ -12804,6 +12814,7 @@ void ImGui::BeginGroup() group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupLogLinePosY = window->DC.LogLinePosY; group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; group_data.AdvanceCursor = true; window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; @@ -12839,11 +12850,13 @@ void ImGui::EndGroup() ItemAdd(group_bb, 0); } - // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will be functional on the entire group. - // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context. - const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow); - if (active_id_within_group) + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. + // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but put a little more burden on individual widgets. + // (and if you grep for LastItemId you'll notice it is only used in that context. + if (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow) window->DC.LastItemId = g.ActiveId; + else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow) + window->DC.LastItemId = g.ActiveIdPreviousFrame; window->DC.LastItemRect = group_bb; window->DC.GroupStack.pop_back(); diff --git a/imgui.h b/imgui.h index 233e0f653..e2dfa1a3c 100644 --- a/imgui.h +++ b/imgui.h @@ -504,6 +504,7 @@ namespace ImGui IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(0) && IsItemHovered() IMGUI_API bool IsItemVisible(); // is the last item visible? (aka not out of sight due to clipping/scrolling.) + IMGUI_API bool IsItemDeactivated(); // is the last item just made inactive (item was previously active), useful for Undo/Redo patterns. IMGUI_API bool IsAnyItemHovered(); IMGUI_API bool IsAnyItemActive(); IMGUI_API bool IsAnyItemFocused(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 53367a080..34e3e154c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2028,7 +2028,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::TreePop(); } - if (ImGui::TreeNode("Focused & Hovered Test")) + if (ImGui::TreeNode("Active, Focused & Hovered Test")) { static bool embed_all_inside_a_child_window = false; ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); @@ -2068,16 +2068,22 @@ void ImGui::ShowDemoWindow(bool* p_open) // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code) ImGui::Button("ITEM"); ImGui::BulletText( + "IsItemFocused() = %d\n" "IsItemHovered() = %d\n" "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" "IsItemHovered(_AllowWhenOverlapped) = %d\n" - "IsItemhovered(_RectOnly) = %d\n", + "IsItemHovered(_RectOnly) = %d\n" + "IsItemActive() = %d\n" + "IsItemDeactivated() = %d\n", + ImGui::IsItemFocused(), ImGui::IsItemHovered(), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), - ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)); + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), + ImGui::IsItemDeactivated()); ImGui::BeginChild("child", ImVec2(0,50), true); ImGui::Text("This is another child window for testing IsWindowHovered() flags."); diff --git a/imgui_internal.h b/imgui_internal.h index 1ef9ce9dd..f6e4e057a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -394,6 +394,7 @@ struct ImGuiGroupData float BackupCurrentLineTextBaseOffset; float BackupLogLinePosY; bool BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; bool AdvanceCursor; }; @@ -624,9 +625,11 @@ struct ImGuiContext bool ActiveIdIsAlive; // Active widget has been seen this frame bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdPreviousFrameIsAlive; int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; + ImGuiWindow* ActiveIdPreviousFrameWindow; ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. @@ -762,9 +765,10 @@ struct ImGuiContext ActiveIdIsAlive = false; ActiveIdIsJustActivated = false; ActiveIdAllowOverlap = false; + ActiveIdPreviousFrameIsAlive = false; ActiveIdAllowNavDirFlags = 0; ActiveIdClickOffset = ImVec2(-1,-1); - ActiveIdWindow = NULL; + ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; ActiveIdSource = ImGuiInputSource_None; LastActiveId = 0; LastActiveIdTimer = 0.0f; From 3569d74f98307660227481f8583f7261fa88b951 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Jun 2018 18:51:23 +0200 Subject: [PATCH 03/11] Demo: Moved test of the Hovered/Active/Focused functions to the Widgets section. --- imgui_demo.cpp | 151 +++++++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 67 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 34e3e154c..2c2279853 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -396,6 +396,7 @@ void ImGui::ShowDemoWindow(bool* p_open) const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; static int listbox_item_current = 1; ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + ImGui::Text("Hovered %d, Active %d, Deactivated %d", ImGui::IsItemHovered(), ImGui::IsItemActive(), ImGui::IsItemDeactivated()); //static int listbox_item_current2 = 2; //ImGui::PushItemWidth(-1); @@ -1172,6 +1173,89 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::PopStyleVar(); ImGui::TreePop(); } + + if (ImGui::TreeNode("Active, Focused, Hovered & Focused Tests")) + { + // Testing IsItemHovered() and other functions with their various flags. Note that the flags can be combined. + // (because BulletText is an item itself and that would affect the output of IsItemHovered() we pass all state in a single call to simplify the code). + static int item_type = 1; + static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; + ImGui::RadioButton("Text", &item_type, 0); ImGui::SameLine(); + ImGui::RadioButton("Button", &item_type, 1); ImGui::SameLine(); + ImGui::RadioButton("Multi-Component", &item_type, 2); + bool return_value = false; + if (item_type == 0) + ImGui::Text("ITEM: Text"); + if (item_type == 1) + return_value = ImGui::Button("ITEM: Button"); + if (item_type == 2) + return_value = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); + ImGui::BulletText( + "Return value = %d\n" + "IsItemFocused() = %d\n" + "IsItemHovered() = %d\n" + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemHovered(_RectOnly) = %d\n" + "IsItemActive() = %d\n" + "IsItemDeactivated() = %d\n" + "IsItemVisible() = %d\n", + return_value, + ImGui::IsItemFocused(), + ImGui::IsItemHovered(), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), + ImGui::IsItemDeactivated(), + ImGui::IsItemVisible() + ); + + static bool embed_all_inside_a_child_window = false; + ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); + if (embed_all_inside_a_child_window) + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true); + + // Testing IsWindowFocused() function with its various flags. Note that the flags can be combined. + ImGui::BulletText( + "IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + + // Testing IsWindowHovered() function with its various flags. Note that the flags can be combined. + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" + "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_AnyWindow) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + 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::EndChild(); + if (embed_all_inside_a_child_window) + EndChild(); + + ImGui::TreePop(); + } } if (ImGui::CollapsingHeader("Layout")) @@ -2028,73 +2112,6 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::TreePop(); } - if (ImGui::TreeNode("Active, Focused & Hovered Test")) - { - static bool embed_all_inside_a_child_window = false; - ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); - if (embed_all_inside_a_child_window) - ImGui::BeginChild("embeddingchild", ImVec2(0, ImGui::GetFontSize() * 25), true); - - // Testing IsWindowFocused() function with its various flags (note that the flags can be combined) - ImGui::BulletText( - "IsWindowFocused() = %d\n" - "IsWindowFocused(_ChildWindows) = %d\n" - "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" - "IsWindowFocused(_RootWindow) = %d\n" - "IsWindowFocused(_AnyWindow) = %d\n", - ImGui::IsWindowFocused(), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); - - // Testing IsWindowHovered() function with its various flags (note that the flags can be combined) - ImGui::BulletText( - "IsWindowHovered() = %d\n" - "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" - "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsWindowHovered(_ChildWindows) = %d\n" - "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" - "IsWindowHovered(_RootWindow) = %d\n" - "IsWindowHovered(_AnyWindow) = %d\n", - ImGui::IsWindowHovered(), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); - - // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code) - ImGui::Button("ITEM"); - ImGui::BulletText( - "IsItemFocused() = %d\n" - "IsItemHovered() = %d\n" - "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" - "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsItemHovered(_AllowWhenOverlapped) = %d\n" - "IsItemHovered(_RectOnly) = %d\n" - "IsItemActive() = %d\n" - "IsItemDeactivated() = %d\n", - ImGui::IsItemFocused(), - ImGui::IsItemHovered(), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), - ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), - ImGui::IsItemActive(), - ImGui::IsItemDeactivated()); - - ImGui::BeginChild("child", ImVec2(0,50), true); - ImGui::Text("This is another child window for testing IsWindowHovered() flags."); - ImGui::EndChild(); - - if (embed_all_inside_a_child_window) - EndChild(); - - ImGui::TreePop(); - } - if (ImGui::TreeNode("Dragging")) { ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); From be4b8b5615043ff75b102db017590e939d5643fc Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 12 Jun 2018 20:18:51 +0200 Subject: [PATCH 04/11] Internals: Added GetItemID(), GetFocusID() for consistency. Made GetActiveID() inline. Comments, fixed typos, demo tweaks. --- examples/imgui_impl_opengl2.cpp | 2 +- examples/imgui_impl_opengl2.h | 2 +- examples/imgui_impl_opengl3.cpp | 2 +- examples/imgui_impl_opengl3.h | 2 +- imgui.cpp | 6 ------ imgui.h | 24 +++++++++++++----------- imgui_demo.cpp | 22 +++++++++++----------- imgui_internal.h | 12 +++++++----- 8 files changed, 35 insertions(+), 37 deletions(-) diff --git a/examples/imgui_impl_opengl2.cpp b/examples/imgui_impl_opengl2.cpp index a47b07736..54337dbf7 100644 --- a/examples/imgui_impl_opengl2.cpp +++ b/examples/imgui_impl_opengl2.cpp @@ -2,7 +2,7 @@ // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLUint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** // **Prefer using the code in imgui_impl_opengl3.cpp** diff --git a/examples/imgui_impl_opengl2.h b/examples/imgui_impl_opengl2.h index 1d7ac8c3e..7da3cfa14 100644 --- a/examples/imgui_impl_opengl2.h +++ b/examples/imgui_impl_opengl2.h @@ -2,7 +2,7 @@ // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLUint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** // **Prefer using the code in imgui_impl_opengl3.cpp** diff --git a/examples/imgui_impl_opengl3.cpp b/examples/imgui_impl_opengl3.cpp index 80d5d1143..a24af5524 100644 --- a/examples/imgui_impl_opengl3.cpp +++ b/examples/imgui_impl_opengl3.cpp @@ -3,7 +3,7 @@ // (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLUint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // CHANGELOG // (minor and older changes stripped away, please see git history for details) diff --git a/examples/imgui_impl_opengl3.h b/examples/imgui_impl_opengl3.h index 56115cdb4..24bfd6e14 100644 --- a/examples/imgui_impl_opengl3.h +++ b/examples/imgui_impl_opengl3.h @@ -3,7 +3,7 @@ // (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLUint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // About GLSL version: // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. diff --git a/imgui.cpp b/imgui.cpp index 825a63d12..296280c08 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2199,12 +2199,6 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) } } -ImGuiID ImGui::GetActiveID() -{ - ImGuiContext& g = *GImGui; - return g.ActiveId; -} - void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index e2dfa1a3c..1dbb34e61 100644 --- a/imgui.h +++ b/imgui.h @@ -314,10 +314,11 @@ 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 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 ArrowButton(const char* str_id, ImGuiDir dir); 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.) + IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool Checkbox(const char* label, bool* v); @@ -399,8 +400,9 @@ 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 - IMGUI_API bool TreeNode(const char* label); // if returning 'true' the node is open and the tree id is pushed into the id stack. user is responsible for calling TreePop(). - IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // 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(). + // 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); // " IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); @@ -409,7 +411,7 @@ namespace ImGui IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); - IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call Push/Pop yourself for layout purpose + IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); // ~ Unindent()+PopId() IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing() @@ -434,10 +436,10 @@ namespace ImGui IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); // Tooltips - IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set text tooltip under mouse-cursor, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip(). - IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of contents). + IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). IMGUI_API void EndTooltip(); + 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); // Menus IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. @@ -500,11 +502,11 @@ namespace ImGui // Utilities 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- items that don't interact will always return false) + 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? - IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(0) && IsItemHovered() - IMGUI_API bool IsItemVisible(); // is the last item visible? (aka not out of sight due to clipping/scrolling.) - IMGUI_API bool IsItemDeactivated(); // is the last item just made inactive (item was previously active), useful for Undo/Redo patterns. + IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() + IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active), useful for Undo/Redo patterns. IMGUI_API bool IsAnyItemHovered(); IMGUI_API bool IsAnyItemActive(); IMGUI_API bool IsAnyItemFocused(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2c2279853..46fbbf668 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -396,7 +396,6 @@ void ImGui::ShowDemoWindow(bool* p_open) const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; static int listbox_item_current = 1; ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); - ImGui::Text("Hovered %d, Active %d, Deactivated %d", ImGui::IsItemHovered(), ImGui::IsItemActive(), ImGui::IsItemDeactivated()); //static int listbox_item_current2 = 2; //ImGui::PushItemWidth(-1); @@ -1176,20 +1175,21 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Active, Focused, Hovered & Focused Tests")) { - // Testing IsItemHovered() and other functions with their various flags. Note that the flags can be combined. + // Display the value of IsItemHovered() and other common item state functions. Note that the flags can be combined. // (because BulletText is an item itself and that would affect the output of IsItemHovered() we pass all state in a single call to simplify the code). static int item_type = 1; static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; ImGui::RadioButton("Text", &item_type, 0); ImGui::SameLine(); ImGui::RadioButton("Button", &item_type, 1); ImGui::SameLine(); - ImGui::RadioButton("Multi-Component", &item_type, 2); - bool return_value = false; - if (item_type == 0) - ImGui::Text("ITEM: Text"); - if (item_type == 1) - return_value = ImGui::Button("ITEM: Button"); - if (item_type == 2) - return_value = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); + ImGui::RadioButton("SliderFloat", &item_type, 2); ImGui::SameLine(); + ImGui::RadioButton("ColorEdit4", &item_type, 3); ImGui::SameLine(); + ImGui::RadioButton("ListBox", &item_type, 4); + bool ret = false; + if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction + if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button + if (item_type == 2) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item + if (item_type == 3) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 4) { const char* items[] = { "Apple", "Banana", "Cherry" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } ImGui::BulletText( "Return value = %d\n" "IsItemFocused() = %d\n" @@ -1201,7 +1201,7 @@ void ImGui::ShowDemoWindow(bool* p_open) "IsItemActive() = %d\n" "IsItemDeactivated() = %d\n" "IsItemVisible() = %d\n", - return_value, + ret, ImGui::IsItemFocused(), ImGui::IsItemHovered(), ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), diff --git a/imgui_internal.h b/imgui_internal.h index f6e4e057a..99718db1c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1039,8 +1039,8 @@ struct ImGuiItemHoveredDataBackup ImRect LastItemDisplayRect; ImGuiItemHoveredDataBackup() { Backup(); } - void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } - void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } + void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } + void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } }; //----------------------------------------------------------------------------- @@ -1053,7 +1053,7 @@ namespace ImGui // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) // If this ever crash because g.CurrentWindow is NULL it means that either // - ImGui::NewFrame() has never been called, which is illegal. - // - You are calling ImGui functions after ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. + // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByName(const char* name); @@ -1073,12 +1073,14 @@ namespace ImGui IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); + inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } + inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } + inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); - IMGUI_API ImGuiID GetActiveID(); IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); IMGUI_API void ClearActiveID(); - IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API ImGuiID GetHoveredID(); + IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); From d57fc7fb970524dbaadb9622704ba666053840c0 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Jun 2018 00:10:33 +0200 Subject: [PATCH 05/11] Added IsItemDeactivatedAfterChange() if the last item was active previously, isn't anymore, and during its active state modified a value. Note that you may still get false positive. (#820, #956, #1875) --- CHANGELOG.txt | 4 +++- imgui.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++-- imgui.h | 3 ++- imgui_demo.cpp | 17 ++++++++++------ imgui_internal.h | 5 +++++ 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c471d45d9..3db9e2718 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -63,7 +63,9 @@ Other Changes: - 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 but isn't anymore. Useful for Undo/Redo patterns. (#820, #956, #1875) + - 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() if the last item was active previously, isn't 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) - TreeNode: Fixed nodes with ImGuiTreeNodeFlags_Leaf flag always returning true which was meaningless. diff --git a/imgui.cpp b/imgui.cpp index 296280c08..fce6cf8cc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2182,6 +2182,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) if (g.ActiveIdIsJustActivated) { g.ActiveIdTimer = 0.0f; + g.ActiveIdValueChanged = false; if (id != 0) { g.LastActiveId = id; @@ -2249,6 +2250,15 @@ void ImGui::KeepAliveID(ImGuiID id) g.ActiveIdPreviousFrameIsAlive = true; } +void ImGui::MarkItemValueChanged(ImGuiID id) +{ + // This marking is solely to be able to provide info for IsItemDeactivatedAfterChange(). + // 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. + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId == id || g.ActiveId == 0); + g.ActiveIdValueChanged = true; +} + static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) { // An active popup disable hovering on other windows (apart from its own children) @@ -3716,6 +3726,7 @@ void ImGui::NewFrame() g.LastActiveIdTimer += g.IO.DeltaTime; g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdPreviousFrameValueChanged = g.ActiveIdValueChanged; g.ActiveIdIsAlive = g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) @@ -4982,6 +4993,12 @@ bool ImGui::IsItemDeactivated() return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); } +bool ImGui::IsItemDeactivatedAfterChange() +{ + ImGuiContext& g = *GImGui; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameValueChanged || (g.ActiveId == 0 && g.ActiveIdValueChanged)); +} + bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; @@ -8022,6 +8039,8 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags |= ImGuiButtonFlags_Repeat; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + if (pressed) + MarkItemValueChanged(id); // Render const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); @@ -9327,6 +9346,8 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co // Actual slider behavior + render grab ItemSize(total_bb, style.FramePadding.y); const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power); + if (value_changed) + MarkItemValueChanged(id); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; @@ -9380,7 +9401,9 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d } // Actual slider behavior + render grab - bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical); + if (value_changed) + MarkItemValueChanged(id); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. // For the vertical slider we allow centered text to overlap the frame padding @@ -9657,6 +9680,8 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa // Actual drag behavior ItemSize(total_bb, style.FramePadding.y); const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power); + if (value_changed) + MarkItemValueChanged(id); // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); @@ -10005,7 +10030,10 @@ bool ImGui::Checkbox(const char* label, bool* v) bool hovered, held; bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); if (pressed) + { *v = !(*v); + MarkItemValueChanged(id); + } RenderNavHighlight(total_bb, id); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); @@ -10073,6 +10101,8 @@ bool ImGui::RadioButton(const char* label, bool active) bool hovered, held; bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + MarkItemValueChanged(id); RenderNavHighlight(total_bb, id); window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); @@ -10969,6 +10999,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + if (value_changed) + MarkItemValueChanged(id); + if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) return enter_pressed; else @@ -11433,6 +11466,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl g.NavDisableHighlight = true; SetNavID(id, window->DC.NavLayerCurrent); } + if (pressed) + MarkItemValueChanged(id); // Render if (hovered || selected) @@ -12025,6 +12060,9 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + if (pressed) + MarkItemValueChanged(id); + return pressed; } @@ -12319,6 +12357,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) window->DC.LastItemId = g.ActiveId; + if (value_changed) + MarkItemValueChanged(window->DC.LastItemId); + return value_changed; } @@ -12642,9 +12683,15 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } EndGroup(); + + if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) + value_changed = false; + if (value_changed) + MarkItemValueChanged(window->DC.LastItemId); + PopID(); - return value_changed && memcmp(backup_initial_col, col, components * sizeof(float)); + return value_changed; } // Horizontal separating line. @@ -12752,6 +12799,8 @@ bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float *size1 += mouse_delta; *size2 -= mouse_delta; bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); + + MarkItemValueChanged(id); } // Render diff --git a/imgui.h b/imgui.h index 1dbb34e61..f6b952ac2 100644 --- a/imgui.h +++ b/imgui.h @@ -506,7 +506,8 @@ namespace ImGui IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? IMGUI_API bool IsItemClicked(int mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) - IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active), useful for Undo/Redo patterns. + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. + IMGUI_API bool IsItemDeactivatedAfterChange(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). IMGUI_API bool IsAnyItemHovered(); IMGUI_API bool IsAnyItemActive(); IMGUI_API bool IsAnyItemFocused(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 46fbbf668..9b3271aa4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1178,18 +1178,21 @@ void ImGui::ShowDemoWindow(bool* p_open) // Display the value of IsItemHovered() and other common item state functions. Note that the flags can be combined. // (because BulletText is an item itself and that would affect the output of IsItemHovered() we pass all state in a single call to simplify the code). static int item_type = 1; + static bool b = false; static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; ImGui::RadioButton("Text", &item_type, 0); ImGui::SameLine(); ImGui::RadioButton("Button", &item_type, 1); ImGui::SameLine(); - ImGui::RadioButton("SliderFloat", &item_type, 2); ImGui::SameLine(); - ImGui::RadioButton("ColorEdit4", &item_type, 3); ImGui::SameLine(); - ImGui::RadioButton("ListBox", &item_type, 4); + ImGui::RadioButton("CheckBox", &item_type, 2); ImGui::SameLine(); + ImGui::RadioButton("SliderFloat", &item_type, 3); ImGui::SameLine(); + ImGui::RadioButton("ColorEdit4", &item_type, 4); ImGui::SameLine(); + ImGui::RadioButton("ListBox", &item_type, 5); bool ret = false; if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button - if (item_type == 2) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item - if (item_type == 3) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 4) { const char* items[] = { "Apple", "Banana", "Cherry" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + if (item_type == 2) { ret = ImGui::Checkbox("ITEM: CheckBox", &b); } // Testing checkbox + if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item + if (item_type == 4) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 5) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } ImGui::BulletText( "Return value = %d\n" "IsItemFocused() = %d\n" @@ -1200,6 +1203,7 @@ void ImGui::ShowDemoWindow(bool* p_open) "IsItemHovered(_RectOnly) = %d\n" "IsItemActive() = %d\n" "IsItemDeactivated() = %d\n" + "IsItemDeactivatedAfterChange() = %d\n" "IsItemVisible() = %d\n", ret, ImGui::IsItemFocused(), @@ -1210,6 +1214,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), ImGui::IsItemActive(), ImGui::IsItemDeactivated(), + ImGui::IsItemDeactivatedAfterChange(), ImGui::IsItemVisible() ); diff --git a/imgui_internal.h b/imgui_internal.h index 99718db1c..cc9d16c9b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -625,7 +625,9 @@ struct ImGuiContext bool ActiveIdIsAlive; // Active widget has been seen this frame bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdValueChanged; bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameValueChanged; int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; @@ -765,7 +767,9 @@ struct ImGuiContext ActiveIdIsAlive = false; ActiveIdIsJustActivated = false; ActiveIdAllowOverlap = false; + ActiveIdValueChanged = false; ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameValueChanged = false; ActiveIdAllowNavDirFlags = 0; ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; @@ -1082,6 +1086,7 @@ namespace ImGui IMGUI_API ImGuiID GetHoveredID(); IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); + IMGUI_API void MarkItemValueChanged(ImGuiID id); IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); From 335f6fde7e23f19f3b2900223b6d0eaefb838e44 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Jun 2018 13:36:48 +0200 Subject: [PATCH 06/11] Comments + missing changelog bits in 1.52 for SetNextWindowPos, SetNextWindowPosCenter. (obsolete #771) --- CHANGELOG.txt | 16 +++++++++------- imgui.h | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 3db9e2718..caa986add 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -462,6 +462,7 @@ Breaking Changes: - Renamed `AlignFirstTextHeightToWidgets()` to `AlignTextToFramePadding()`. Kept inline redirection function (will obsolete). - Obsoleted the legacy 5 parameters version of Begin(). Please avoid using it. If you need a transparent window background, uses `PushStyleColor()`. The old size parameter there was also misleading and equivalent to calling `SetNextWindowSize(size, ImGuiCond_FirstTimeEver)`. Kept inline redirection function (will obsolete). - Obsoleted `IsItemHoveredRect()`, `IsMouseHoveringWindow()` in favor of using the newly introduced flags of `IsItemHovered()` and `IsWindowHovered()`. Kept inline redirection function (will obsolete). (#1382) +- Obsoleted 'SetNextWindowPosCenter()' in favor of using 1SetNextWindowPos()` with a pivot value which allows to do the same and more. Keep inline redirection function. - 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. @@ -490,13 +491,14 @@ Other Changes: - Trees: Fixed calling `SetNextTreeNodeOpen()` on a collapsed window leaking to the first tree node item of the next frame. - Layout: Horizontal layout is automatically enforced in a menu bar, so you can use non-MenuItem elements without calling SameLine(). - Separator: Output a vertical separator when used inside a menu bar (or in general when horizontal layout is active, but that isn't exposed yet!). -- Windows: Added `IsWindowAppearing()` helper (helpful e.g. as a condition before initializing some of your own things.). -- Windows: Fixed title bar color of top-most window under a modal window. -- Windows: Fixed not being able to move a window by clicking on one of its child window. (#1337, #635) -- Windows: Fixed `Begin()` auto-fit calculation code that predict the presence of a scrollbar so it works better when window size constraints are used. -- Windows: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which in turn would set enable the Appearing condition for that frame. -- Windows: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow user creating a window called "Debug" without losing their custom flags. -- Windows: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move the parent window by clicking on SubChild. (#1381) +- Window: Added `IsWindowAppearing()` helper (helpful e.g. as a condition before initializing some of your own things.). +- Window: Added pivot parameter to `SetNextWindowPos()`, making it possible to center or right align a window. Obsoleted `SetNextWindowPosCenter()`. +- Window: Fixed title bar color of top-most window under a modal window. +- Window: Fixed not being able to move a window by clicking on one of its child window. (#1337, #635) +- Window: Fixed `Begin()` auto-fit calculation code that predict the presence of a scrollbar so it works better when window size constraints are used. +- Window: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which in turn would set enable the Appearing condition for that frame. +- Window: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow user creating a window called "Debug" without losing their custom flags. +- Window: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move the parent window by clicking on SubChild. (#1381) - Popups: Pop-ups can be closed with a right-click anywhere, without altering focus under the pop-up. (~#439) - Popups: `BeginPopupContextItem()`, `BeginPopupContextWindow()` are now setup to allow reopening a context menu by right-clicking again. (~#439) - Popups: `BeginPopupContextItem()` now supports a NULL string identifier and uses the last item ID if available. diff --git a/imgui.h b/imgui.h index f6b952ac2..927c1d946 100644 --- a/imgui.h +++ b/imgui.h @@ -139,12 +139,12 @@ struct ImVec4 #endif }; -// ImGui end-user API -// In a namespace so that user can add extra functions in your own separate file (please don't modify imgui.cpp/.h) +// Dear ImGui end-user API +// (In a namespace so you can add extra functions in your own separate file. Please don't modify imgui.cpp/.h!) namespace ImGui { // Context creation and access - // All contexts share a same ImFontAtlas by default. If you want different font atlas, you can new() them and overwrite the GetIO().Fonts variable of an ImGui context. + // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts. // All those functions are not reliant on the current context. IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context @@ -153,8 +153,8 @@ namespace ImGui IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert); // Main - IMGUI_API ImGuiIO& GetIO(); - IMGUI_API ImGuiStyle& GetStyle(); + IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame. IMGUI_API void NewFrame(); // start a new ImGui frame, you can submit any command from this point until Render()/EndFrame(). IMGUI_API void Render(); // ends the ImGui frame, finalize the draw data. (Obsolete: optionally call io.RenderDrawListsFn if set. Nowadays, prefer calling your render function yourself.) IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. (Obsolete: this used to be passed to your io.RenderDrawListsFn() function.) @@ -820,9 +820,9 @@ enum ImGuiConfigFlags_ ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. - ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag with io.NavActive is set. - ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information back-end - ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end. + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. // 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. @@ -832,8 +832,8 @@ enum ImGuiConfigFlags_ // Back-end capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom back-end. enum ImGuiBackendFlags_ { - ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end supports and has a connected gamepad. - ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end supports reading GetMouseCursor() to change the OS cursor shape. + ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end supports honoring GetMouseCursor() value to change the OS cursor shape. ImGuiBackendFlags_HasSetMousePos = 1 << 2 // Back-end supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). }; From 185b4dde8778d30e8f861e1dc8d83541a6352647 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Jun 2018 19:22:22 +0200 Subject: [PATCH 07/11] Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. Added clipboard support. Unindexing buffers ourselves as Allegro indexed drawing primitives are buggy in the DirectX9 back-end. --- CHANGELOG.txt | 3 +- examples/.gitignore | 1 + examples/example_allegro5/README.md | 4 +- .../example_allegro5/example_allegro5.vcxproj | 173 ++++++++++++++++++ .../example_allegro5.vcxproj.filters | 52 ++++++ examples/imgui_impl_allegro5.cpp | 105 ++++++++--- examples/imgui_impl_sdl.cpp | 1 + 7 files changed, 315 insertions(+), 24 deletions(-) create mode 100644 examples/example_allegro5/example_allegro5.vcxproj create mode 100644 examples/example_allegro5/example_allegro5.vcxproj.filters diff --git a/CHANGELOG.txt b/CHANGELOG.txt index caa986add..979f5cd19 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -82,7 +82,8 @@ Other Changes: - 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: Added SDL+Vulkan example. - - Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. + - 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. - Examples: FreeGLUT: Added FreeGLUT bindings. Added FreeGLUT+OpenGL2 example. (#801) - Misc: Updated stb_textedit from 1.09 + patches to 1.12 + minor patches. - Internals: PushItemFlag() flags are inherited by BeginChild(). diff --git a/examples/.gitignore b/examples/.gitignore index db2859e1d..2b8e1eadc 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -10,6 +10,7 @@ build/* *.o *.obj *.exe +*.log *.pdb *.ilk *.VC.db diff --git a/examples/example_allegro5/README.md b/examples/example_allegro5/README.md index 783839db3..5fdcc5047 100644 --- a/examples/example_allegro5/README.md +++ b/examples/example_allegro5/README.md @@ -12,12 +12,12 @@ Note that the back-end supports _BOTH_ 16-bit and 32-bit indices, but 32-bit ind - On Ubuntu 14.04+ ```bash -g++ -DIMGUI_USER_CONFIG=\"examples/example_allegro5/imconfig_allegro5.h\" -I .. -I ../.. main.cpp imgui_impl_allegro5.cpp ../../imgui*.cpp -lallegro -lallegro_primitives -o allegro5_example +g++ -DIMGUI_USER_CONFIG=\"examples/example_allegro5/imconfig_allegro5.h\" -I .. -I ../.. main.cpp ..\imgui_impl_allegro5.cpp ../../imgui*.cpp -lallegro -lallegro_primitives -o allegro5_example ``` - On Windows with Visual Studio's CLI ``` set ALLEGRODIR=path_to_your_allegro5_folder -cl /Zi /MD /I %ALLEGRODIR%\include /DIMGUI_USER_CONFIG=\"examples/example_allegro5/imconfig_allegro5.h\" /I .. /I ..\.. main.cpp imgui_impl_allegro5.cpp ..\..\imgui*.cpp /link /LIBPATH:%ALLEGRODIR%\lib allegro-5.0.10-monolith-md.lib user32.lib +cl /Zi /MD /I %ALLEGRODIR%\include /DIMGUI_USER_CONFIG=\"examples/example_allegro5/imconfig_allegro5.h\" /I .. /I ..\.. main.cpp ..\imgui_impl_allegro5.cpp ..\..\imgui*.cpp /link /LIBPATH:%ALLEGRODIR%\lib allegro-5.0.10-monolith-md.lib user32.lib ``` diff --git a/examples/example_allegro5/example_allegro5.vcxproj b/examples/example_allegro5/example_allegro5.vcxproj new file mode 100644 index 000000000..ec96f6211 --- /dev/null +++ b/examples/example_allegro5/example_allegro5.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741} + example_allegro5 + + + + Application + true + MultiByte + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + + + + + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + + Level4 + Disabled + ..\..;..;%(AdditionalIncludeDirectories) + + + true + %(AdditionalLibraryDirectories) + opengl32.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + Disabled + ..\..;..;%(AdditionalIncludeDirectories) + + + true + %(AdditionalLibraryDirectories) + opengl32.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + MaxSpeed + true + true + ..\..;..;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories) + false + + + true + true + true + %(AdditionalLibraryDirectories) + opengl32.lib;%(AdditionalDependencies) + Console + + + + + + + Level4 + MaxSpeed + true + true + ..\..;..;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories) + false + + + true + true + true + %(AdditionalLibraryDirectories) + opengl32.lib;%(AdditionalDependencies) + Console + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/example_allegro5/example_allegro5.vcxproj.filters b/examples/example_allegro5/example_allegro5.vcxproj.filters new file mode 100644 index 000000000..09dbc5ebc --- /dev/null +++ b/examples/example_allegro5/example_allegro5.vcxproj.filters @@ -0,0 +1,52 @@ + + + + + {20b90ce4-7fcb-4731-b9a0-075f875de82d} + + + {f18ab499-84e1-499f-8eff-9754361e0e52} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + imgui + + + imgui + + + imgui + + + sources + + + sources + + + sources + + + + + imgui + + + imgui + + + imgui + + + sources + + + + + + sources + + + \ No newline at end of file diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp index 5855b9f8e..5126a3c28 100644 --- a/examples/imgui_impl_allegro5.cpp +++ b/examples/imgui_impl_allegro5.cpp @@ -3,10 +3,11 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. +// [X] Platform: Clipboard support (from Allegro 5.1.12) // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. + // Issues: -// [ ] Renderer: The renderer is suboptimal as we need to convert vertices. -// [ ] Platform: Clipboard support via al_set_clipboard_text/al_clipboard_has_text. +// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert the format of vertices. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). @@ -15,6 +16,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12). +// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle. // 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. // 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp. // 2018-04-18: Misc: Added support for 32-bits vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h. @@ -26,12 +30,19 @@ #include // memcpy #include "imgui.h" #include "imgui_impl_allegro5.h" + +// Allegro #include #include - #ifdef _WIN32 #include #endif +#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12 + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#endif // Data static ALLEGRO_DISPLAY* g_Display = NULL; @@ -39,6 +50,7 @@ static ALLEGRO_BITMAP* g_Texture = NULL; static double g_Time = 0.0; static ALLEGRO_MOUSE_CURSOR* g_MouseCursorInvisible = NULL; static ALLEGRO_VERTEX_DECL* g_VertexDecl = NULL; +static char* g_ClipboardTextData = NULL; struct ImDrawVertAllegro { @@ -51,32 +63,53 @@ struct ImDrawVertAllegro // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) { - int op, src, dst; - al_get_blender(&op, &src, &dst); + // Backup Allegro state that will be modified + ALLEGRO_TRANSFORM last_transform = *al_get_current_transform(); + ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform(); + int last_clip_x, last_clip_y, last_clip_w, last_clip_h; + al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h); + int last_blender_op, last_blender_src, last_blender_dst; + al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst); + + // Setup render state al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); + // Setup orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). + { + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + ALLEGRO_TRANSFORM transform; + al_identity_transform(&transform); + al_use_transform(&transform); + al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f); + al_use_projection_transform(&transform); + } + for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - // FIXME-OPT: Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats + // Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves. + // FIXME-OPT: Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 float as well.. static ImVector vertices; - vertices.resize(cmd_list->VtxBuffer.Size); - for (int i = 0; i < cmd_list->VtxBuffer.Size; ++i) + vertices.resize(cmd_list->IdxBuffer.Size); + for (int i = 0; i < cmd_list->IdxBuffer.Size; i++) { - const ImDrawVert &dv = cmd_list->VtxBuffer[i]; - ImDrawVertAllegro v; - v.pos = dv.pos; - v.uv = dv.uv; - unsigned char *c = (unsigned char*)&dv.col; - v.col = al_map_rgba(c[0], c[1], c[2], c[3]); - vertices[i] = v; + const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]]; + ImDrawVertAllegro* dst_v = &vertices[i]; + dst_v->pos = src_v->pos; + dst_v->uv = src_v->uv; + unsigned char* c = (unsigned char*)&src_v->col; + dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]); } const int* indices = NULL; if (sizeof(ImDrawIdx) == 2) { - // FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request ImGui to output 32-bit indices. + // FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request ImGui to output 32-bit indices. // Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful. static ImVector indices_converted; indices_converted.resize(cmd_list->IdxBuffer.Size); @@ -90,6 +123,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) } int idx_offset = 0; + ImVec2 pos = draw_data->DisplayPos; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; @@ -100,16 +134,18 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) else { ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->TextureId; - al_set_clipping_rectangle(pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z-pcmd->ClipRect.x, pcmd->ClipRect.w-pcmd->ClipRect.y); - al_draw_indexed_prim(&vertices[0], g_VertexDecl, texture, &indices[idx_offset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); + al_set_clipping_rectangle(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y); + al_draw_prim(&vertices[0], g_VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); } idx_offset += pcmd->ElemCount; } } - // Restore modified state - al_set_blender(op, src, dst); - al_set_clipping_rectangle(0, 0, al_get_display_width(g_Display), al_get_display_height(g_Display)); + // Restore modified Allegro state + al_set_blender(last_blender_op, last_blender_src, last_blender_dst); + al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h); + al_use_transform(&last_transform); + al_use_projection_transform(&last_projection_transform); } bool ImGui_ImplAllegro5_CreateDeviceObjects() @@ -174,6 +210,21 @@ void ImGui_ImplAllegro5_InvalidateDeviceObjects() } } +#if ALLEGRO_HAS_CLIPBOARD +static const char* ImGui_ImplAllegro5_GetClipboardText(void*) +{ + if (g_ClipboardTextData) + al_free(g_ClipboardTextData); + g_ClipboardTextData = al_get_clipboard_text(g_Display); + return g_ClipboardTextData; +} + +static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text) +{ + al_set_clipboard_text(g_Display, text); +} +#endif + bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) { g_Display = display; @@ -216,12 +267,24 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y; io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z; +#if ALLEGRO_HAS_CLIPBOARD + io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; + io.ClipboardUserData = NULL; +#endif + return true; } void ImGui_ImplAllegro5_Shutdown() { ImGui_ImplAllegro5_InvalidateDeviceObjects(); + g_Display = NULL; + + // Destroy last known clipboard data + if (g_ClipboardTextData) + al_free(g_ClipboardTextData); + g_ClipboardTextData = NULL; } // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 309bcf9b6..4027d5f0a 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -190,6 +190,7 @@ void ImGui_ImplSDL2_Shutdown() // Destroy last known clipboard data if (g_ClipboardTextData) SDL_free(g_ClipboardTextData); + g_ClipboardTextData = NULL; // Destroy SDL mouse cursors for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_Count_; cursor_n++) From 2a6fbb2197fa54e4317227bcdcaf91f718af09a0 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Jun 2018 22:22:52 +0200 Subject: [PATCH 08/11] Speculative fix for Win32 clipboard handler if SetClipboardText() fails + Minor fix for static analyzer + using :: prefix when calling in Win32 functions. --- imgui.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fce6cf8cc..dca0bc30a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12694,7 +12694,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl return value_changed; } -// Horizontal separating line. +// Horizontal/vertical separating line void ImGui::Separator() { ImGuiWindow* window = GetCurrentWindow(); @@ -12702,9 +12702,8 @@ void ImGui::Separator() return; ImGuiContext& g = *GImGui; - ImGuiSeparatorFlags flags = 0; - if ((flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)) == 0) - flags |= (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + // Those flags should eventually be overridable by the user + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)))); // Check that only 1 option is selected if (flags & ImGuiSeparatorFlags_Vertical) { @@ -13672,42 +13671,43 @@ static const char* GetClipboardTextFn_DefaultImpl(void*) { static ImVector buf_local; buf_local.clear(); - if (!OpenClipboard(NULL)) + if (!::OpenClipboard(NULL)) return NULL; - HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT); + HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); if (wbuf_handle == NULL) { - CloseClipboard(); + ::CloseClipboard(); return NULL; } - if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle)) + if (ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle)) { int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; buf_local.resize(buf_len); ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL); } - GlobalUnlock(wbuf_handle); - CloseClipboard(); + ::GlobalUnlock(wbuf_handle); + ::CloseClipboard(); return buf_local.Data; } static void SetClipboardTextFn_DefaultImpl(void*, const char* text) { - if (!OpenClipboard(NULL)) + if (!::OpenClipboard(NULL)) return; const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; - HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); + HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); if (wbuf_handle == NULL) { - CloseClipboard(); + ::CloseClipboard(); return; } - ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle); + ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle); ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL); - GlobalUnlock(wbuf_handle); - EmptyClipboard(); - SetClipboardData(CF_UNICODETEXT, wbuf_handle); - CloseClipboard(); + ::GlobalUnlock(wbuf_handle); + ::EmptyClipboard(); + if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) + ::GlobalFree(wbuf_handle); + ::CloseClipboard(); } #else @@ -13744,13 +13744,13 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) { // Notify OS Input Method Editor of text input position if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle) - if (HIMC himc = ImmGetContext(hwnd)) + if (HIMC himc = ::ImmGetContext(hwnd)) { COMPOSITIONFORM cf; cf.ptCurrentPos.x = x; cf.ptCurrentPos.y = y; cf.dwStyle = CFS_FORCE_POSITION; - ImmSetCompositionWindow(himc, &cf); + ::ImmSetCompositionWindow(himc, &cf); } } From ce0b36ba101487267dcef17b59aa3865769c24f3 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 13 Jun 2018 23:20:09 +0200 Subject: [PATCH 09/11] Added _None values to various enum flags, useful for readability and some coding style likes it. (Unfortunately we can't refer to them as default value in imgui.h functions because they need to be declared below). --- imgui.cpp | 4 ++-- imgui.h | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index dca0bc30a..2881f617c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2684,7 +2684,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; if (!IsMouseHoveringRect(bb.Min, bb.Max)) return false; - if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_Default)) + if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) return false; if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) return false; @@ -5007,7 +5007,7 @@ bool ImGui::IsItemFocused() bool ImGui::IsItemClicked(int mouse_button) { - return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_Default); + return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); } bool ImGui::IsAnyItemHovered() diff --git a/imgui.h b/imgui.h index 927c1d946..4386cc368 100644 --- a/imgui.h +++ b/imgui.h @@ -582,6 +582,7 @@ namespace ImGui // Flags for ImGui::Begin() enum ImGuiWindowFlags_ { + ImGuiWindowFlags_None = 0, ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window @@ -616,6 +617,7 @@ enum ImGuiWindowFlags_ // Flags for ImGui::InputText() enum ImGuiInputTextFlags_ { + ImGuiInputTextFlags_None = 0, ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z @@ -641,6 +643,7 @@ enum ImGuiInputTextFlags_ // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() enum ImGuiTreeNodeFlags_ { + ImGuiTreeNodeFlags_None = 0, ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one @@ -666,6 +669,7 @@ enum ImGuiTreeNodeFlags_ // Flags for ImGui::Selectable() enum ImGuiSelectableFlags_ { + ImGuiSelectableFlags_None = 0, ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) ImGuiSelectableFlags_AllowDoubleClick = 1 << 2 // Generate press events on double clicks too @@ -674,6 +678,7 @@ enum ImGuiSelectableFlags_ // Flags for ImGui::BeginCombo() enum ImGuiComboFlags_ { + ImGuiComboFlags_None = 0, ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) @@ -687,6 +692,7 @@ enum ImGuiComboFlags_ // Flags for ImGui::IsWindowFocused() enum ImGuiFocusedFlags_ { + ImGuiFocusedFlags_None = 0, ImGuiFocusedFlags_ChildWindows = 1 << 0, // IsWindowFocused(): Return true if any children of the window is focused ImGuiFocusedFlags_RootWindow = 1 << 1, // IsWindowFocused(): Test from root window (top most parent of the current hierarchy) ImGuiFocusedFlags_AnyWindow = 1 << 2, // IsWindowFocused(): Return true if any window is focused @@ -697,7 +703,7 @@ enum ImGuiFocusedFlags_ // Note: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that. Please read the FAQ! enum ImGuiHoveredFlags_ { - ImGuiHoveredFlags_Default = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered @@ -712,6 +718,7 @@ enum ImGuiHoveredFlags_ // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() enum ImGuiDragDropFlags_ { + ImGuiDragDropFlags_None = 0, // BeginDragDropSource() flags ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. @@ -930,6 +937,7 @@ enum ImGuiStyleVar_ // Enumeration for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() enum ImGuiColorEditFlags_ { + ImGuiColorEditFlags_None = 0, ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (read 3 components from the input pointer). ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on colored square. ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. From 826d77185e5967b5d572304945e37102efb58181 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 14 Jun 2018 15:10:46 +0200 Subject: [PATCH 10/11] Revert 640c0566: TreeNode: Fixed nodes with ImGuiTreeNodeFlags_Leaf flag always returning true which was meaningless -> more flexible to keep allowing it by default so it setup an ID scope. --- CHANGELOG.txt | 1 - imgui.cpp | 2 +- imgui_demo.cpp | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 979f5cd19..1d4fe60bd 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -68,7 +68,6 @@ Other Changes: 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) - - TreeNode: Fixed nodes with ImGuiTreeNodeFlags_Leaf flag always returning true which was meaningless. - 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) diff --git a/imgui.cpp b/imgui.cpp index 2881f617c..e779356f2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8323,7 +8323,7 @@ void ImGui::LogButtons() bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) { if (flags & ImGuiTreeNodeFlags_Leaf) - return false; + return true; // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions) ImGuiContext& g = *GImGui; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9b3271aa4..a2d555ffd 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -458,7 +458,7 @@ void ImGui::ShowDemoWindow(bool* p_open) else { // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text(). - node_flags |= ImGuiTreeNodeFlags_Leaf; // | ImGuiTreeNodeFlags_Bullet; + node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); if (ImGui::IsItemClicked()) node_clicked = i; From b5d385824db2f204527713d6d6ad02c24a9ccef8 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 14 Jun 2018 15:02:43 +0200 Subject: [PATCH 11/11] Added assert in TreePop() to ease catching ID stack underflow earlier. --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index e779356f2..beefcfcd7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13323,6 +13323,7 @@ void ImGui::TreePop() } window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1; + IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. PopID(); }