From f33eb890180f75ac2f7faf8a2dd8290f924a35b2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Aug 2014 15:43:58 +0100 Subject: [PATCH 01/12] Fix tooltip data needlessly leaking into .ini file --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 05ef8c1f..a1eb0c42 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1783,7 +1783,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin ImGuiWindow* window = FindWindow(name); if (!window) { - if (flags & ImGuiWindowFlags_ChildWindow) + if (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) { window = new ImGuiWindow(name, ImVec2(0,0), size); } From 6c11d7623e304875b198345fc381f32ab794bded Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Aug 2014 15:51:55 +0100 Subject: [PATCH 02/12] Fix invalid .ini file data persistently saving back on next save --- imgui.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a1eb0c42..d6cfa8cb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1116,11 +1116,13 @@ static void SaveSettings() return; for (size_t i = 0; i != g.Settings.size(); i++) { - const ImGuiIniData* ini = g.Settings[i]; - fprintf(f, "[%s]\n", ini->Name); - fprintf(f, "Pos=%d,%d\n", (int)ini->Pos.x, (int)ini->Pos.y); - fprintf(f, "Size=%d,%d\n", (int)ini->Size.x, (int)ini->Size.y); - fprintf(f, "Collapsed=%d\n", ini->Collapsed); + const ImGuiIniData* settings = g.Settings[i]; + if (settings->Pos.x == FLT_MAX) + continue; + fprintf(f, "[%s]\n", settings->Name); + fprintf(f, "Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); + fprintf(f, "Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); + fprintf(f, "Collapsed=%d\n", settings->Collapsed); fprintf(f, "\n"); } From a4b96445e879ab3671913da5fea105db31256f89 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Aug 2014 16:02:42 +0100 Subject: [PATCH 03/12] Fix typo and speculative warning --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d6cfa8cb..0e0dc348 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2091,7 +2091,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); } - // Innter clipping rectangle + // Inner clipping rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame const ImGuiAabb title_bar_aabb = window->TitleBarAabb(); ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x-1.5f, window->Aabb().Max.y-1.5f); @@ -5239,7 +5239,7 @@ static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_en return; if (!text_end) text_end = text + strlen(text); - const int buf_length = (text_end - text) + 1; + const int buf_length = (int)(text_end - text) + 1; HGLOBAL buf_handle = GlobalAlloc(GMEM_MOVEABLE, buf_length * sizeof(char)); if (buf_handle == NULL) return; From 9169b2911c28ea2080c56885a2b0f8aa6e8f1f9f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Aug 2014 17:01:42 +0100 Subject: [PATCH 04/12] Fixed trailing \n reporting extra text height --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 0e0dc348..d24436c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5079,7 +5079,7 @@ ImVec2 ImBitmapFont::CalcTextSize(float size, float max_width, const char* text_ text_size.y += line_height; line_width = 0; } - if (const FntGlyph* glyph = FindGlyph((unsigned short)c)) + else if (const FntGlyph* glyph = FindGlyph((unsigned short)c)) { const float char_width = (glyph->XAdvance + Info->SpacingHoriz) * scale; //const float char_extend = (glyph->XOffset + glyph->Width * scale); From 2bc6346b48bbacfb383f099f69a86ede82cc85be Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 12:32:53 +0100 Subject: [PATCH 05/12] Added TextColored() helper. Changed some parameters to const references (still allows implicit casting) --- imgui.cpp | 30 ++++++++++++++++++++++++------ imgui.h | 13 +++++++------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d24436c3..3fb30a74 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1697,7 +1697,7 @@ void SetTooltip(const char* fmt, ...) va_end(args); } -void SetNewWindowDefaultPos(ImVec2 pos) +void SetNewWindowDefaultPos(const ImVec2& pos) { ImGuiState& g = GImGui; g.NewWindowDefaultPos = pos; @@ -2196,7 +2196,7 @@ void PopAllowKeyboardFocus() window->DC.AllowKeyboardFocus.pop_back(); } -void PushStyleColor(ImGuiCol idx, ImVec4 col) +void PushStyleColor(ImGuiCol idx, const ImVec4& col) { ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -2284,7 +2284,7 @@ ImVec2 GetWindowPos() return window->Pos; } -void SetWindowPos(ImVec2 pos) +void SetWindowPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); window->Pos = pos; @@ -2342,10 +2342,10 @@ ImVec2 GetCursorPos() return window->DC.CursorPos - window->Pos; } -void SetCursorPos(ImVec2 p) +void SetCursorPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.CursorPos = window->Pos + p; + window->DC.CursorPos = window->Pos + pos; } void SetScrollPosHere() @@ -2385,6 +2385,16 @@ void Text(const char* fmt, ...) va_end(args); } +void TextColored(const ImVec4& col, const char* fmt, ...) +{ + ImGui::PushStyleColor(ImGuiCol_Text, col); + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); + ImGui::PopStyleColor(); +} + void TextUnformatted(const char* text, const char* text_end) { ImGuiState& g = GImGui; @@ -4409,7 +4419,7 @@ bool IsClipped(const ImGuiAabb& bb) return false; } -bool IsClipped(ImVec2 item_size) +bool IsClipped(const ImVec2& item_size) { ImGuiWindow* window = GetCurrentWindow(); return IsClipped(ImGuiAabb(window->DC.CursorPos, window->DC.CursorPos + item_size)); @@ -5441,6 +5451,14 @@ void ShowTestWindow(bool* open) ImGui::TreePop(); } + if (ImGui::TreeNode("Colored Text")) + { + // This is a merely a shortcut, you can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink"); + ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow"); + ImGui::TreePop(); + } + static int e = 0; ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); diff --git a/imgui.h b/imgui.h index b0063304..897b897d 100644 --- a/imgui.h +++ b/imgui.h @@ -135,7 +135,7 @@ namespace ImGui bool GetWindowIsFocused(); float GetWindowWidth(); ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to use your own drawing - void SetWindowPos(ImVec2 pos); // unchecked + void SetWindowPos(const ImVec2& pos); // unchecked ImVec2 GetWindowSize(); ImVec2 GetWindowContentRegionMin(); ImVec2 GetWindowContentRegionMax(); @@ -149,7 +149,7 @@ namespace ImGui float GetItemWidth(); void PushAllowKeyboardFocus(bool v); void PopAllowKeyboardFocus(); - void PushStyleColor(ImGuiCol idx, ImVec4 col); + void PushStyleColor(ImGuiCol idx, const ImVec4& col); void PopStyleColor(); // Layout @@ -161,8 +161,8 @@ namespace ImGui float GetColumnOffset(int column_index = -1); void SetColumnOffset(int column_index, float offset); float GetColumnWidth(int column_index = -1); - ImVec2 GetCursorPos(); // cursor position relative to window position - void SetCursorPos(ImVec2 p); + ImVec2 GetCursorPos(); // cursor position is relative to window position + void SetCursorPos(const ImVec2& pos); // " void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match higher widgets. float GetTextLineSpacing(); float GetTextLineHeight(); @@ -176,6 +176,7 @@ namespace ImGui // Widgets void Text(const char* fmt, ...); void TextV(const char* fmt, va_list args); + void TextColored(const ImVec4& col, const char* fmt, ...); // shortcut to doing PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, better for long chunks of text. void LabelText(const char* label, const char* fmt, ...); void BulletText(const char* fmt, ...); @@ -230,11 +231,11 @@ namespace ImGui // Utilities void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). (currently no contention handling, last call win) - void SetNewWindowDefaultPos(ImVec2 pos); // set position of window that do + void SetNewWindowDefaultPos(const ImVec2& pos); // set position of window that do bool IsHovered(); // was the last item active area hovered by mouse? ImVec2 GetItemBoxMin(); // get bounding box of last item ImVec2 GetItemBoxMax(); // get bounding box of last item - bool IsClipped(ImVec2 item_size); // to perform coarse clipping on user's side (as an optimisation) + bool IsClipped(const ImVec2& item_size); // to perform coarse clipping on user's side (as an optimisation) bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry bool IsMouseClicked(int button, bool repeat = false); bool IsMouseDoubleClicked(int button); From 1509b8f63411eeebe75837fce7a888f62446468e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 12:35:39 +0100 Subject: [PATCH 06/12] Added TODO list items from users feedback --- imgui.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 3fb30a74..a586265e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -109,6 +109,8 @@ ISSUES AND TODO-LIST + - misc: allow user to call NewFrame() multiple times without a render. + - misc: add extra mouse buttons for user storage (and clarify that ImGui doesn't use them) - misc: merge ImVec4 / ImGuiAabb, they are essentially duplicate containers - window: autofit is losing its purpose when user relies on any dynamic layout (window width multiplier, column). maybe just discard autofit? - window: support horizontal scroll @@ -135,6 +137,7 @@ - file selection widget -> build the tool in our codebase to improve model-dialog idioms (may or not lead to ImGui changes) - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - slider: initial absolute click is unprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. + - treenode: ignore click when keyboard modifiers are pressed so that users can catch them for other purposes. - text edit: centered text for slider or input text to it matches typical positionning. - text edit: flag to disable live update of the user buffer. - text edit: field resize behaviour - field could stretch when being edited? hover tooltip shows more text? @@ -147,6 +150,7 @@ - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) - keyboard: full keyboard navigation and focus - misc: not thread-safe + - tooltip: add a BeginTooltip()/EndTooltip() helper. - optimisation/render: use indexed rendering - optimisation/render: move clip-rect to vertex data? would allow merging all commands - optimisation/render: merge command-list of all windows into one command-list? From 6267905a1749862625c1f389aac1722736d4262c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 16:18:00 +0100 Subject: [PATCH 07/12] Added BeginTooltip()/EndTooltip() helpers to create tooltips with custom widgets --- imgui.cpp | 113 +++++++++++++++++++++++++++++++++++++++--------------- imgui.h | 8 +++- 2 files changed, 88 insertions(+), 33 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a586265e..40fca47a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -132,6 +132,7 @@ - combo: turn child handling code into popup helper - list selection, concept of a selectable "block" (that can be multiple widgets) - menubar, menus + - plot: plot lines draws 1 item too much? - plot: add a stride parameter? - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID) - file selection widget -> build the tool in our codebase to improve model-dialog idioms (may or not lead to ImGui changes) @@ -194,6 +195,7 @@ static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true); static bool CloseWindowButton(bool* open = NULL); static void FocusWindow(ImGuiWindow* window); +static ImGuiWindow* FindWindow(const char* name); static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs); }; // namespace ImGui @@ -1372,7 +1374,7 @@ void Render() ImGui::End(); // Sort the window list so that all child windows are after their parent - // When cannot do that on FocusWindow() because childs may not exist yet + // We cannot do that on FocusWindow() because childs may not exist yet ImVector sorted_windows; sorted_windows.reserve(g.Windows.size()); for (size_t i = 0; i != g.Windows.size(); i++) @@ -1391,34 +1393,28 @@ void Render() memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); } + // Render tooltip + if (g.Tooltip[0]) + { + // Use a dummy window to render the tooltip + ImGui::BeginTooltip(); + ImGui::TextUnformatted(g.Tooltip); + ImGui::EndTooltip(); + } + // Gather windows to render g.RenderDrawLists.resize(0); for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (!window->Visible) - continue; - if (window->Flags & ImGuiWindowFlags_ChildWindow) - continue; - window->AddToRenderList(); + if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) + window->AddToRenderList(); } - - // Render tooltip - if (g.Tooltip[0]) + for (size_t i = 0; i != g.Windows.size(); i++) { - // Use a dummy window to render the tooltip - ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), 0.0f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_Tooltip); - ImGuiWindow* window = GetCurrentWindow(); - //window->DrawList->Clear(); - ImGui::PushClipRect(ImVec4(-9999,-9999,+9999,+9999), false); - const ImVec2 text_size = CalcTextSize(g.Tooltip, NULL, false); - const ImVec2 pos = g.IO.MousePos + ImVec2(32,16); - const ImGuiAabb bb(pos - g.Style.FramePadding*2, pos + text_size + g.Style.FramePadding*2); - ImGui::RenderFrame(bb.Min, bb.Max, window->Color(ImGuiCol_TooltipBg), false, g.Style.WindowRounding); - ImGui::RenderText(pos, g.Tooltip, NULL, false); - ImGui::PopClipRect(); - ImGui::End(); - window->AddToRenderList(); + ImGuiWindow* window = g.Windows[i]; + if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip)) + window->AddToRenderList(); } // Render @@ -1726,6 +1722,17 @@ static ImGuiWindow* FindWindow(const char* name) return NULL; } +void BeginTooltip() +{ + ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), 0.9f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_Tooltip); +} + +void EndTooltip() +{ + IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Tooltip); + ImGui::End(); +} + void BeginChild(const char* str_id, ImVec2 size, bool border, ImGuiWindowFlags extra_flags) { ImGuiState& g = GImGui; @@ -1824,12 +1831,21 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin const bool first_begin_of_the_frame = (window->LastFrameDrawn != current_frame); if (first_begin_of_the_frame) { - // New windows appears in front - if (window->LastFrameDrawn < current_frame - 1) - ImGui::FocusWindow(window); - window->DrawList->Clear(); window->Visible = true; + + // New windows appears in front + if (window->LastFrameDrawn < current_frame - 1) + { + ImGui::FocusWindow(window); + if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + { + // Hide for 1 frame while resizing + window->AutoFitFrames = 2; + window->Visible = false; + } + } + window->LastFrameDrawn = current_frame; window->ClipRectStack.resize(0); @@ -1871,6 +1887,12 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin } } + // Tooltips always follow mouse + if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + { + window->PosFloat = g.IO.MousePos + ImVec2(32,16) - g.Style.FramePadding*2; + } + // Clamp into view if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) { @@ -1884,7 +1906,12 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin { window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); } - window->ItemWidthDefault = (float)(int)(window->Size.x > 0.0f ? window->Size.x * 0.65f : 250.0f); + + // Default item width + if (window->Size.x > 0.0f && !(window->Flags & ImGuiWindowFlags_Tooltip)) + window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f); + else + window->ItemWidthDefault = 200.0f; // Prepare for focus requests if (window->FocusIdxRequestNext == IM_INT_MAX || window->FocusIdxCounter == -1) @@ -1939,9 +1966,17 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin { window->Size = window->SizeFull; - // Draw resize grip + // Draw resize grip and resize ImU32 resize_col = 0; - if (!(window->Flags & ImGuiWindowFlags_NoResize)) + if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + { + if (window->AutoFitFrames > 0) + { + // Tooltip always resize + window->SizeFull = window->SizeContentsFit + g.Style.WindowPadding - ImVec2(0.0f, g.Style.ItemSpacing.y); + } + } + else if (!(window->Flags & ImGuiWindowFlags_NoResize)) { const ImGuiAabb resize_aabb(window->Aabb().GetBR()-ImVec2(18,18), window->Aabb().GetBR()); const ImGuiID resize_id = window->GetID("#RESIZE"); @@ -1949,7 +1984,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin ButtonBehaviour(resize_aabb, resize_id, &hovered, &held); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); - const ImVec2 size_auto_fit = ImClamp(window->SizeContentsFit + style.AutoFitPadding, style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding); + ImVec2 size_auto_fit = ImClamp(window->SizeContentsFit + style.AutoFitPadding, style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding); if (window->AutoFitFrames > 0) { // Auto-fit only grows during the first few frames @@ -2291,7 +2326,12 @@ ImVec2 GetWindowPos() void SetWindowPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); - window->Pos = pos; + const ImVec2 old_pos = window->Pos; + window->PosFloat = pos; + window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); + + // If we happen to move the window while it is showing (which is a bad idea) let's at least offset the cursor + window->DC.CursorPos += (window->Pos - old_pos); } ImVec2 GetWindowSize() @@ -5472,6 +5512,17 @@ void ShowTestWindow(bool* open) if (ImGui::IsHovered()) ImGui::SetTooltip("I am a tooltip"); + ImGui::SameLine(); + ImGui::Text("- or me"); + if (ImGui::IsHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::EndTooltip(); + } + static int item = 1; ImGui::Combo("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); diff --git a/imgui.h b/imgui.h index 897b897d..57be4ee8 100644 --- a/imgui.h +++ b/imgui.h @@ -135,7 +135,7 @@ namespace ImGui bool GetWindowIsFocused(); float GetWindowWidth(); ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to use your own drawing - void SetWindowPos(const ImVec2& pos); // unchecked + void SetWindowPos(const ImVec2& pos); // set current window pos ImVec2 GetWindowSize(); ImVec2 GetWindowContentRegionMin(); ImVec2 GetWindowContentRegionMax(); @@ -152,6 +152,11 @@ namespace ImGui void PushStyleColor(ImGuiCol idx, const ImVec4& col); void PopStyleColor(); + // Tooltip + void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins. + void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text. + void EndTooltip(); + // Layout void Separator(); // horizontal line void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets to layout them horizontally @@ -230,7 +235,6 @@ namespace ImGui void LogToClipboard(int max_depth = -1); // Utilities - void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). (currently no contention handling, last call win) void SetNewWindowDefaultPos(const ImVec2& pos); // set position of window that do bool IsHovered(); // was the last item active area hovered by mouse? ImVec2 GetItemBoxMin(); // get bounding box of last item From fa0aa5ace64612e28969f55d1d29659a0ec15aa4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 16:22:03 +0100 Subject: [PATCH 08/12] Added storage for up to 5 mouse buttons for convenience (even though ImGui itself only uses 1) --- imgui.cpp | 2 -- imgui.h | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 40fca47a..39ff7be4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -110,7 +110,6 @@ ISSUES AND TODO-LIST - misc: allow user to call NewFrame() multiple times without a render. - - misc: add extra mouse buttons for user storage (and clarify that ImGui doesn't use them) - misc: merge ImVec4 / ImGuiAabb, they are essentially duplicate containers - window: autofit is losing its purpose when user relies on any dynamic layout (window width multiplier, column). maybe just discard autofit? - window: support horizontal scroll @@ -151,7 +150,6 @@ - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) - keyboard: full keyboard navigation and focus - misc: not thread-safe - - tooltip: add a BeginTooltip()/EndTooltip() helper. - optimisation/render: use indexed rendering - optimisation/render: move clip-rect to vertex data? would allow merging all commands - optimisation/render: merge command-list of all windows into one command-list? diff --git a/imgui.h b/imgui.h index 57be4ee8..1145d76c 100644 --- a/imgui.h +++ b/imgui.h @@ -402,7 +402,7 @@ struct ImGuiIO // Input - Fill before calling NewFrame() ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) - bool MouseDown[2]; // Mouse buttons + bool MouseDown[5]; // Mouse buttons. ImGui itself only uses button 0 (left button) but you can use others as storage for convenience. int MouseWheel; // Mouse wheel: -1,0,+1 bool KeyCtrl; // Keyboard modifier pressed: Control bool KeyShift; // Keyboard modifier pressed: Shift @@ -419,11 +419,11 @@ struct ImGuiIO // [Internal] ImGui will maintain those fields for you ImVec2 MousePosPrev; ImVec2 MouseDelta; - bool MouseClicked[2]; - ImVec2 MouseClickedPos[2]; - float MouseClickedTime[2]; - bool MouseDoubleClicked[2]; - float MouseDownTime[2]; + bool MouseClicked[5]; + ImVec2 MouseClickedPos[5]; + float MouseClickedTime[5]; + bool MouseDoubleClicked[5]; + float MouseDownTime[5]; float KeysDownTime[512]; ImGuiIO(); From 152878571e4b090c81d54d0dae2716277873117d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 16:38:29 +0100 Subject: [PATCH 09/12] TreeNode/CollapsingHeader ignore clicks when CTRL or SHFIT are held + make default button hover brighter --- imgui.cpp | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 39ff7be4..ce5bf7a0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -129,6 +129,7 @@ - columns: columns header to act as button (~sort op) and allow resize/reorder - columns: user specify columns size - combo: turn child handling code into popup helper + - combo: slow down mouse wheel scroll speed - list selection, concept of a selectable "block" (that can be multiple widgets) - menubar, menus - plot: plot lines draws 1 item too much? @@ -137,7 +138,6 @@ - file selection widget -> build the tool in our codebase to improve model-dialog idioms (may or not lead to ImGui changes) - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - slider: initial absolute click is unprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. - - treenode: ignore click when keyboard modifiers are pressed so that users can catch them for other purposes. - text edit: centered text for slider or input text to it matches typical positionning. - text edit: flag to disable live update of the user buffer. - text edit: field resize behaviour - field could stretch when being edited? hover tooltip shows more text? @@ -153,6 +153,7 @@ - optimisation/render: use indexed rendering - optimisation/render: move clip-rect to vertex data? would allow merging all commands - optimisation/render: merge command-list of all windows into one command-list? + - optimisation/render: font exported by bmfont is not tight fit on vertical axis, incur unneeded pixel-shading cost. - optimisation: turn some the various stack vectors into statically-sized arrays - optimisation: better clipping for multi-component widgets - optimisation: specialize for height based clipping first (assume widgets never go up + height tests before width tests?) @@ -176,7 +177,7 @@ namespace ImGui { -static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered = NULL, bool* out_held = NULL, bool repeat = false); +static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false); static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, const bool hide_text_after_hash = true); static ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, const bool hide_text_after_hash = true); @@ -241,7 +242,7 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); Colors[ImGuiCol_Button] = ImVec4(0.67f, 0.40f, 0.40f, 0.60f); - Colors[ImGuiCol_ButtonHovered] = ImVec4(0.60f, 0.40f, 0.40f, 1.00f); + Colors[ImGuiCol_ButtonHovered] = ImVec4(0.67f, 0.40f, 0.40f, 1.00f); Colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); Colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); Colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); @@ -1979,7 +1980,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin const ImGuiAabb resize_aabb(window->Aabb().GetBR()-ImVec2(18,18), window->Aabb().GetBR()); const ImGuiID resize_id = window->GetID("#RESIZE"); bool hovered, held; - ButtonBehaviour(resize_aabb, resize_id, &hovered, &held); + ButtonBehaviour(resize_aabb, resize_id, &hovered, &held, true); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); ImVec2 size_auto_fit = ImClamp(window->SizeContentsFit + style.AutoFitPadding, style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding); @@ -2047,7 +2048,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin if (grab_size_y_norm < 1.0f) { const ImGuiID scrollbar_id = window->GetID("#SCROLLY"); - ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held); + ButtonBehaviour(scrollbar_bb, scrollbar_id, &hovered, &held, true); if (held) { g.HoveredId = scrollbar_id; @@ -2576,7 +2577,7 @@ void LabelText(const char* label, const char* fmt, ...) RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y), label); } -static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool repeat) +static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat) { ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -2586,13 +2587,16 @@ static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_ho if (hovered) { g.HoveredId = id; - if (g.IO.MouseClicked[0]) + if (allow_key_modifiers || (!g.IO.KeyCtrl && !g.IO.KeyShift)) { - g.ActiveId = id; - } - else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true)) - { - pressed = true; + if (g.IO.MouseClicked[0]) + { + g.ActiveId = id; + } + else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true)) + { + pressed = true; + } } } @@ -2640,7 +2644,7 @@ bool Button(const char* label, ImVec2 size, bool repeat_when_held) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held, repeat_when_held); + bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true, repeat_when_held); // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); @@ -2674,7 +2678,7 @@ bool SmallButton(const char* label) return false; bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held); + bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); // Render const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); @@ -2694,7 +2698,7 @@ static bool CloseWindowButton(bool* open) const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-title_bar_height+3.0f,2.0f), window->Aabb().GetTR() + ImVec2(-2.0f,+title_bar_height-2.0f)); bool hovered, held; - bool pressed = ButtonBehaviour(bb, id, &hovered, &held); + bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true); // Render const ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); @@ -2831,7 +2835,7 @@ bool CollapsingHeader(const char* label, const char* str_id, const bool display_ return opened; bool hovered, held; - bool pressed = ButtonBehaviour(display_frame ? bb : text_bb, id, &hovered, &held); + bool pressed = ButtonBehaviour(display_frame ? bb : text_bb, id, &hovered, &held, false); if (pressed) { opened = !opened; @@ -4089,10 +4093,12 @@ bool Combo(const char* label, int* current_item, bool (*items_getter)(void*, int if (ClipAdvance(frame_bb)) return false; + const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(bb); + bool value_changed = false; ItemSize(frame_bb); RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg)); - RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, window->Color(ImGuiCol_Button)); + RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, window->Color(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button)); RenderCollapseTriangle(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y) + style.FramePadding, true); if (*current_item >= 0 && *current_item < items_count) @@ -4106,7 +4112,6 @@ bool Combo(const char* label, int* current_item, bool (*items_getter)(void*, int ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); ImGui::PushID(id); - const bool hovered = (g.HoveredWindow == window) && (g.HoveredId == 0) && IsMouseHoveringBox(bb); bool menu_toggled = false; if (hovered) { @@ -4143,7 +4148,7 @@ bool Combo(const char* label, int* current_item, bool (*items_getter)(void*, int const ImGuiID item_id = child_window->GetID((void*)(intptr_t)item_idx); bool item_hovered, item_held; - bool item_pressed = ButtonBehaviour(item_aabb, item_id, &item_hovered, &item_held); + bool item_pressed = ButtonBehaviour(item_aabb, item_id, &item_hovered, &item_held, true); bool item_selected = item_idx == *current_item; if (item_hovered || item_selected) @@ -4587,7 +4592,7 @@ void Columns(int columns_count, const char* id, bool border) continue; bool hovered, held; - ButtonBehaviour(column_aabb, column_id, &hovered, &held); + ButtonBehaviour(column_aabb, column_id, &hovered, &held, true); // Draw before resize so our items positioning are in sync with the line const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column); From 868ba05a13c3144fe3eb6f17523932a0ee73dc79 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 16:40:31 +0100 Subject: [PATCH 10/12] Slowed down mouse wheel scrolling speed in combo boxes --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ce5bf7a0..1343eda4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -129,7 +129,6 @@ - columns: columns header to act as button (~sort op) and allow resize/reorder - columns: user specify columns size - combo: turn child handling code into popup helper - - combo: slow down mouse wheel scroll speed - list selection, concept of a selectable "block" (that can be multiple widgets) - menubar, menus - plot: plot lines draws 1 item too much? @@ -1259,7 +1258,8 @@ void NewFrame() else { // Scroll - window->NextScrollY -= g.IO.MouseWheel * window->FontSize() * 5.0f; + const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5; + window->NextScrollY -= g.IO.MouseWheel * window->FontSize() * scroll_lines; } } From ade21a1ad512d2e956378a83571666f799702304 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 17:36:54 +0100 Subject: [PATCH 11/12] PlotLines(), PlotHistogram(): added a stride parameter. --- imgui.cpp | 30 ++++++++++++++++++------------ imgui.h | 4 ++-- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1343eda4..63dddcc4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -132,7 +132,6 @@ - list selection, concept of a selectable "block" (that can be multiple widgets) - menubar, menus - plot: plot lines draws 1 item too much? - - plot: add a stride parameter? - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID) - file selection widget -> build the tool in our codebase to improve model-dialog idioms (may or not lead to ImGui changes) - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() @@ -3323,7 +3322,13 @@ enum ImGuiPlotType ImGuiPlotType_Histogram, }; -static void Plot(ImGuiPlotType plot_type, const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +static float PlotGetValue(const float* values, size_t stride, int idx) +{ + float v = *(float*)((unsigned char*)values + idx * stride); + return v; +} + +static void Plot(ImGuiPlotType plot_type, const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, size_t stride) { ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -3353,8 +3358,9 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values float v_max = -FLT_MAX; for (int i = 0; i < values_count; i++) { - v_min = ImMin(v_min, values[i]); - v_max = ImMax(v_max, values[i]); + const float v = PlotGetValue(values, stride, i); + v_min = ImMin(v_min, v); + v_max = ImMax(v_max, v); } if (scale_min == FLT_MAX) scale_min = v_min; @@ -3376,8 +3382,8 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values const int v_idx = (int)(t * (values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0))); IM_ASSERT(v_idx >= 0 && v_idx < values_count); - const float v0 = values[(v_idx + values_offset) % values_count]; - const float v1 = values[(v_idx + 1 + values_offset) % values_count]; + const float v0 = PlotGetValue(values, stride, (v_idx + values_offset) % values_count); + const float v1 = PlotGetValue(values, stride, (v_idx + 1 + values_offset) % values_count); if (plot_type == ImGuiPlotType_Lines) ImGui::SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); else if (plot_type == ImGuiPlotType_Histogram) @@ -3387,7 +3393,7 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values const float t_step = 1.0f / (float)res_w; - float v0 = values[(0 + values_offset) % values_count]; + float v0 = PlotGetValue(values, stride, (0 + values_offset) % values_count); float t0 = 0.0f; ImVec2 p0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) / (scale_max - scale_min)) ); @@ -3399,7 +3405,7 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values const float t1 = t0 + t_step; const int v_idx = (int)(t0 * values_count); IM_ASSERT(v_idx >= 0 && v_idx < values_count); - const float v1 = values[(v_idx + values_offset + 1) % values_count]; + const float v1 = PlotGetValue(values, stride, (v_idx + values_offset + 1) % values_count); const ImVec2 p1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) / (scale_max - scale_min)) ); // NB: draw calls are merged into ones @@ -3420,14 +3426,14 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, graph_bb.Min.y), label); } -void PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +void PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, size_t stride) { - ImGui::Plot(ImGuiPlotType_Lines, label, values, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); + ImGui::Plot(ImGuiPlotType_Lines, label, values, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, stride); } -void PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +void PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, size_t stride) { - ImGui::Plot(ImGuiPlotType_Histogram, label, values, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); + ImGui::Plot(ImGuiPlotType_Histogram, label, values, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, stride); } void Checkbox(const char* label, bool* v) diff --git a/imgui.h b/imgui.h index 1145d76c..4e527acf 100644 --- a/imgui.h +++ b/imgui.h @@ -193,8 +193,8 @@ namespace ImGui bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); - void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); - void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); + void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); + void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); void Checkbox(const char* label, bool* v); void CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); bool RadioButton(const char* label, bool active); From f5dbb0a97340b3b342c7fbc6b543bbf00b155b32 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Aug 2014 17:54:42 +0100 Subject: [PATCH 12/12] Fixed floating-point precision issue making the right-side value of a plot sometimes wrap to the left-side value. --- imgui.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 63dddcc4..449580e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -131,7 +131,6 @@ - combo: turn child handling code into popup helper - list selection, concept of a selectable "block" (that can be multiple widgets) - menubar, menus - - plot: plot lines draws 1 item too much? - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID) - file selection widget -> build the tool in our codebase to improve model-dialog idioms (may or not lead to ImGui changes) - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() @@ -3400,7 +3399,7 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values const ImU32 col_base = window->Color((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); const ImU32 col_hovered = window->Color((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); - while (t0 < 1.0f) + for (int n = 0; n < res_w; n++) { const float t1 = t0 + t_step; const int v_idx = (int)(t0 * values_count);