From 6e15b71663f15aeff557f8e2d6040b56a14bb9e7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 16 Aug 2014 14:19:19 +0100 Subject: [PATCH 1/8] Minor todo/readme changes --- README.md | 2 +- imgui.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c3f7767d6..3062cdb40 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Developed by [Omar Cornut](http://www.miracleworld.net). The library was develop Embeds [proggy_clean](http://www.proggyfonts.net/) font by Tristan Grimmer (also MIT license). -Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Matt Willis. Thanks! +Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Thanks! License ------- diff --git a/imgui.cpp b/imgui.cpp index 449580e3e..a193a065a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -109,6 +109,7 @@ ISSUES AND TODO-LIST + - main: window title clipping is broken. - misc: allow user to call NewFrame() multiple times without a render. - 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? @@ -145,7 +146,8 @@ - filters: set a current filter that tree node can automatically query to hide themselves - filters: handle wildcards (with implicit leading/trailing *), regexps - 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 + - input: keyboard: full keyboard navigation and focus. + - input: support trackpad style scrolling. - misc: not thread-safe - optimisation/render: use indexed rendering - optimisation/render: move clip-rect to vertex data? would allow merging all commands From 969b1e0563d2452f7948d3a4cf0d1623561ecef2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 16 Aug 2014 18:22:52 +0100 Subject: [PATCH 2/8] Fix clipping of title bar text. --- imgui.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a193a065a..c6a55bd86 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -109,7 +109,6 @@ ISSUES AND TODO-LIST - - main: window title clipping is broken. - misc: allow user to call NewFrame() multiple times without a render. - 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? @@ -147,7 +146,7 @@ - filters: handle wildcards (with implicit leading/trailing *), regexps - 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) - input: keyboard: full keyboard navigation and focus. - - input: support trackpad style scrolling. + - input: support trackpad style scrolling & slider edit. - misc: not thread-safe - optimisation/render: use indexed rendering - optimisation/render: move clip-rect to vertex data? would allow merging all commands @@ -2115,9 +2114,18 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) { RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true); - RenderText(window->Pos + style.FramePadding + ImVec2(window->FontSize() + style.ItemInnerSpacing.x, 0), name); if (open) ImGui::CloseWindowButton(open); + + const ImVec2 text_size = CalcTextSize(name); + const ImVec2 text_min = window->Pos + style.FramePadding + ImVec2(window->FontSize() + style.ItemInnerSpacing.x, 0.0f); + const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (open ? (title_bar_aabb.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y + text_size.y); + const bool clip_title = text_size.x > (text_max.x - text_min.x); // only push a clip rectangle if we need to, because it may turn into a separate draw call + if (clip_title) + ImGui::PushClipRect(ImVec4(text_min.x, text_min.y, text_max.x, text_max.y)); + RenderText(text_min, name); + if (clip_title) + ImGui::PopClipRect(); } } else @@ -2693,7 +2701,6 @@ static bool CloseWindowButton(bool* open) ImGuiWindow* window = GetCurrentWindow(); const ImGuiID id = window->GetID("##CLOSE"); - const float title_bar_height = window->TitleBarHeight(); 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)); @@ -2703,7 +2710,6 @@ static bool CloseWindowButton(bool* open) // Render const ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); window->DrawList->AddCircleFilled(bb.GetCenter(), ImMax(2.0f,title_bar_height*0.5f-4), col, 16); - //RenderFrame(bb.Min, bb.Max, col, false); const float cross_padding = 4; if (hovered && bb.GetWidth() >= (cross_padding+1)*2 && bb.GetHeight() >= (cross_padding+1)*2) From ddf8b280e9a6bacb8c6347c52516a4a83f54ba26 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 16 Aug 2014 18:47:59 +0100 Subject: [PATCH 3/8] Allowing the user to call NewFrame() multiple times without calling Render() Note that this is never a good idea. But, allowing it reduce confusion in the initial stage of setup. --- imgui.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c6a55bd86..cdee20205 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -109,7 +109,6 @@ ISSUES AND TODO-LIST - - misc: allow user to call NewFrame() multiple times without a render. - 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 @@ -148,6 +147,7 @@ - input: keyboard: full keyboard navigation and focus. - input: support trackpad style scrolling & slider edit. - misc: not thread-safe + - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - 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? @@ -1247,7 +1247,7 @@ void NewFrame() float scale = new_font_scale / window->FontScale; window->FontScale = new_font_scale; - ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; window->Pos += offset; window->PosFloat += offset; window->Size *= scale; @@ -1271,11 +1271,17 @@ void NewFrame() // Mark all windows as not visible for (size_t i = 0; i != g.Windows.size(); i++) - g.Windows[i]->Visible = false; + { + ImGuiWindow* window = g.Windows[i]; + window->Visible = false; + window->Accessed = false; + } + + // No window should be open at the beginning of the frame. + // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. + g.CurrentWindowStack.clear(); - // Create implicit window - // We will only render it if the user has added something to it. - IM_ASSERT(g.CurrentWindowStack.empty()); // No window should be open at the beginning of the frame! + // Create implicit window - we will only render it if the user has added something to it. ImGui::Begin("Debug", NULL, ImVec2(400,400)); } From a165954a692823b9acd98624d471f02cfbe21cf7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 Aug 2014 10:41:36 +0100 Subject: [PATCH 4/8] Reduce inner window clipping to take account for the extend of CollapsingHeader from arikwestbrook --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cdee20205..9339c06f2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2042,7 +2042,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollBarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); //window->DrawList->AddLine(scrollbar_bb.GetTL(), scrollbar_bb.GetBL(), g.Colors[ImGuiCol_Border]); window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg)); - scrollbar_bb.Expand(ImVec2(-3,-3)); + scrollbar_bb.Expand(ImVec2(0,-3)); const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y)); const float grab_size_y = scrollbar_bb.GetHeight() * grab_size_y_norm; @@ -2146,7 +2146,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin // 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); + ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Aabb().Max.y-1.5f); if (window->ScrollbarY) clip_rect.z -= g.Style.ScrollBarWidth; ImGui::PushClipRect(clip_rect); From c32221fa206b13deb9eb8fb5c5ed6f49ed5c6720 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 Aug 2014 11:28:19 +0100 Subject: [PATCH 5/8] Child window with inverted clip rectangles are marked as collapsed. --- imgui.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 9339c06f2..2f996146d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -119,6 +119,7 @@ - main: make IsHovered() more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: make IsHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - scrollbar: use relative mouse movement when first-clicking inside of scroll grab box. + - scrollbar: make the grab visible and a minimum size for long scroll regions - input number: optional range min/max - input number: holding [-]/[+] buttons should increase the step non-linearly - input number: rename Input*() to Input(), Slider*() to Slider() ? @@ -1800,6 +1801,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin ImGuiWindow* window = FindWindow(name); if (!window) { + // Create window the first time, and load settings if (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) { window = new ImGuiWindow(name, ImVec2(0,0), size); @@ -2042,6 +2044,7 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin ImGuiAabb scrollbar_bb(window->Aabb().Max.x - style.ScrollBarWidth, title_bar_aabb.Max.y+1, window->Aabb().Max.x, window->Aabb().Max.y-1); //window->DrawList->AddLine(scrollbar_bb.GetTL(), scrollbar_bb.GetBL(), g.Colors[ImGuiCol_Border]); window->DrawList->AddRectFilled(scrollbar_bb.Min, scrollbar_bb.Max, window->Color(ImGuiCol_ScrollbarBg)); + scrollbar_bb.Max.x -= 3; scrollbar_bb.Expand(ImVec2(0,-3)); const float grab_size_y_norm = ImSaturate(window->Size.y / ImMax(window->SizeContentsFit.y, window->Size.y)); @@ -2138,9 +2141,14 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin { // Outer clipping rectangle if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox)) - ImGui::PushClipRect(g.CurrentWindowStack[g.CurrentWindowStack.size()-2]->ClipRectStack.back()); + { + ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.size()-2]; + ImGui::PushClipRect(parent_window->ClipRectStack.back()); + } else + { ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); + } } // Inner clipping rectangle @@ -2157,6 +2165,21 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin window->Accessed = false; } + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). + if (flags & ImGuiWindowFlags_ChildWindow) + { + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + const ImVec4 clip_rect = window->ClipRectStack.back(); + window->Collapsed = (clip_rect.x >= clip_rect.z || clip_rect.y >= clip_rect.w); + + // We also hide the window from rendering because we've already added its border to the command list. + // (we could perform the check earlier in the function but it is simplier at this point) + // FIXME-WIP + //if (window->Collapsed) + // window->Visible = false; + } + // Return collapsed so that user can perform an early out optimisation return !window->Collapsed; } @@ -4586,6 +4609,8 @@ void Columns(int columns_count, const char* id, bool border) { ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); + if (window->Collapsed) + return; if (window->DC.ColumnsCount != 1) { From 931a4c5b49d175ec94e7bbe8fbd831a967e10243 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 Aug 2014 13:55:27 +0100 Subject: [PATCH 6/8] Renamed ImVector<> members. --- imgui.h | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/imgui.h b/imgui.h index 4e527acf5..3933c25ac 100644 --- a/imgui.h +++ b/imgui.h @@ -62,46 +62,46 @@ template class ImVector { private: - size_t _size; - size_t _capacity; - T* _data; + size_t Size; + size_t Capacity; + T* Data; public: typedef T value_type; typedef value_type* iterator; typedef const value_type* const_iterator; - ImVector() { _size = _capacity = 0; _data = NULL; } - ~ImVector() { if (_data) free(_data); } + ImVector() { Size = Capacity = 0; Data = NULL; } + ~ImVector() { if (Data) free(Data); } - inline bool empty() const { return _size == 0; } - inline size_t size() const { return _size; } - inline size_t capacity() const { return _capacity; } + inline bool empty() const { return Size == 0; } + inline size_t size() const { return Size; } + inline size_t capacity() const { return Capacity; } - inline value_type& at(size_t i) { IM_ASSERT(i < _size); return _data[i]; } - inline const value_type& at(size_t i) const { IM_ASSERT(i < _size); return _data[i]; } - inline value_type& operator[](size_t i) { IM_ASSERT(i < _size); return _data[i]; } - inline const value_type& operator[](size_t i) const { IM_ASSERT(i < _size); return _data[i]; } + inline value_type& at(size_t i) { IM_ASSERT(i < Size); return Data[i]; } + inline const value_type& at(size_t i) const { IM_ASSERT(i < Size); return Data[i]; } + inline value_type& operator[](size_t i) { IM_ASSERT(i < Size); return Data[i]; } + inline const value_type& operator[](size_t i) const { IM_ASSERT(i < Size); return Data[i]; } - inline void clear() { if (_data) { _size = _capacity = 0; free(_data); _data = NULL; } } - inline iterator begin() { return _data; } - inline const_iterator begin() const { return _data; } - inline iterator end() { return _data + _size; } - inline const_iterator end() const { return _data + _size; } + inline void clear() { if (Data) { Size = Capacity = 0; free(Data); Data = NULL; } } + inline iterator begin() { return Data; } + inline const_iterator begin() const { return Data; } + inline iterator end() { return Data + Size; } + inline const_iterator end() const { return Data + Size; } inline value_type& front() { return at(0); } inline const value_type& front() const { return at(0); } - inline value_type& back() { IM_ASSERT(_size > 0); return at(_size-1); } - inline const value_type& back() const { IM_ASSERT(_size > 0); return at(_size-1); } - inline void swap(ImVector& rhs) { const size_t rhs_size = rhs._size; rhs._size = _size; _size = rhs_size; const size_t rhs_cap = rhs._capacity; rhs._capacity = _capacity; _capacity = rhs_cap; value_type* rhs_data = rhs._data; rhs._data = _data; _data = rhs_data; } + inline value_type& back() { IM_ASSERT(Size > 0); return at(Size-1); } + inline const value_type& back() const { IM_ASSERT(Size > 0); return at(Size-1); } + inline void swap(ImVector& rhs) { const size_t rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; const size_t rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } - inline void reserve(size_t new_capacity) { _data = (value_type*)realloc(_data, new_capacity * sizeof(value_type)); _capacity = new_capacity; } - inline void resize(size_t new_size) { if (new_size > _capacity) reserve(new_size); _size = new_size; } + inline void reserve(size_t new_capacity) { Data = (value_type*)realloc(Data, new_capacity * sizeof(value_type)); Capacity = new_capacity; } + inline void resize(size_t new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; } - inline void push_back(const value_type& v) { if (_size == _capacity) reserve(_capacity ? _capacity * 2 : 4); _data[_size++] = v; } - inline void pop_back() { IM_ASSERT(_size > 0); _size--; } + inline void push_back(const value_type& v) { if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); Data[Size++] = v; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } - inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const int off = it - begin(); memmove(_data + off, _data + off + 1, (_size - off - 1) * sizeof(value_type)); _size--; return _data + off; } - inline void insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= begin() && it <= end()); const int off = it - begin(); if (_size == _capacity) reserve(_capacity ? _capacity * 2 : 4); if (off < (int)_size) memmove(_data + off + 1, _data + off, (_size - off) * sizeof(value_type)); _data[off] = v; _size++; } + inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const int off = it - begin(); memmove(Data + off, Data + off + 1, (Size - off - 1) * sizeof(value_type)); Size--; return Data + off; } + inline void insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= begin() && it <= end()); const int off = it - begin(); if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, (Size - off) * sizeof(value_type)); Data[off] = v; Size++; } }; #endif // #ifndef ImVector From f6414f2011554d905c4230be327d74504dce22ae Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 Aug 2014 14:02:32 +0100 Subject: [PATCH 7/8] Invisible child windows gets clipped earlier in the pipeline. --- imgui.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2f996146d..548bc6615 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1003,8 +1003,8 @@ void ImGuiWindow::AddToRenderList() for (size_t i = 0; i < DC.ChildWindows.size(); i++) { ImGuiWindow* child = DC.ChildWindows[i]; - IM_ASSERT(child->Visible); // Shouldn't be in this list if we are not active this frame - child->AddToRenderList(); + if (child->Visible) // clipped childs may have been marked not Visible + child->AddToRenderList(); } } @@ -1334,7 +1334,8 @@ static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector& for (size_t i = 0; i < window->DC.ChildWindows.size(); i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; - AddWindowToSortedBuffer(child, sorted_windows); + if (child->Visible) + AddWindowToSortedBuffer(child, sorted_windows); } } } @@ -2176,8 +2177,8 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin // We also hide the window from rendering because we've already added its border to the command list. // (we could perform the check earlier in the function but it is simplier at this point) // FIXME-WIP - //if (window->Collapsed) - // window->Visible = false; + if (window->Collapsed) + window->Visible = false; } // Return collapsed so that user can perform an early out optimisation From 926f7bfcc504d08764b85e7c58e691c407c164e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 Aug 2014 14:16:10 +0100 Subject: [PATCH 8/8] Added InputFloat4(), SliderFloat4() helpers. --- imgui.cpp | 163 ++++++++++++++++++++++-------------------------------- imgui.h | 2 + 2 files changed, 69 insertions(+), 96 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 548bc6615..e4a3ec2b3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -123,8 +123,7 @@ - input number: optional range min/max - input number: holding [-]/[+] buttons should increase the step non-linearly - input number: rename Input*() to Input(), Slider*() to Slider() ? - - layout: clean up the InputFloat3/SliderFloat3/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper. - - add input4 helper (once above layout helpers are in they'll be smaller) + - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper. - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) - columns: columns header to act as button (~sort op) and allow resize/reorder - columns: user specify columns size @@ -3285,7 +3284,7 @@ bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* disp return changed; } -bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power) +static bool SliderFloatN(const char* label, float v[3], int components, float v_min, float v_max, const char* display_format, float power) { ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -3293,63 +3292,46 @@ bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const return false; const ImGuiStyle& style = g.Style; - - bool value_changed = false; - ImGui::PushID(label); - - const int components = 2; const float w_full = window->DC.ItemWidth.back(); const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)) / (float)components)); const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1))); + bool value_changed = false; + ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); - value_changed |= ImGui::SliderFloat("##X", &v[0], v_min, v_max, display_format, power); - ImGui::SameLine(0, 0); - ImGui::PopItemWidth(); - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::SliderFloat("##Y", &v[1], v_min, v_max, display_format, power); - ImGui::SameLine(0, 0); + for (int i = 0; i < components; i++) + { + ImGui::PushID(i); + if (i + 1 == components) + { + ImGui::PopItemWidth(); + ImGui::PushItemWidth(w_item_last); + } + value_changed |= ImGui::SliderFloat("##v", &v[i], v_min, v_max, display_format, power); + ImGui::SameLine(0, 0); + ImGui::PopID(); + } ImGui::PopItemWidth(); + ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); - ImGui::PopID(); return value_changed; } -bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power) +bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power) { - ImGuiState& g = GImGui; - ImGuiWindow* window = GetCurrentWindow(); - if (window->Collapsed) - return false; - - const ImGuiStyle& style = g.Style; - - bool value_changed = false; - ImGui::PushID(label); - - const int components = 3; - const float w_full = window->DC.ItemWidth.back(); - const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)) / (float)components)); - const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1))); - - ImGui::PushItemWidth(w_item_one); - value_changed |= ImGui::SliderFloat("##X", &v[0], v_min, v_max, display_format, power); - ImGui::SameLine(0, 0); - value_changed |= ImGui::SliderFloat("##Y", &v[1], v_min, v_max, display_format, power); - ImGui::SameLine(0, 0); - ImGui::PopItemWidth(); - - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::SliderFloat("##Z", &v[2], v_min, v_max, display_format, power); - ImGui::SameLine(0, 0); - ImGui::PopItemWidth(); + return SliderFloatN(label, v, 2, v_min, v_max, display_format, power); +} - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); +bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power) +{ + return SliderFloatN(label, v, 3, v_min, v_max, display_format, power); +} - ImGui::PopID(); - return value_changed; +bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format, float power) +{ + return SliderFloatN(label, v, 4, v_min, v_max, display_format, power); } // Enum for ImGui::Plot() @@ -4004,7 +3986,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag return value_changed; } -bool InputFloat2(const char* label, float v[2], int decimal_precision) +static bool InputFloatN(const char* label, float* v, int components, int decimal_precision) { ImGuiState& g = GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -4012,63 +3994,46 @@ bool InputFloat2(const char* label, float v[2], int decimal_precision) return false; const ImGuiStyle& style = g.Style; - - bool value_changed = false; - ImGui::PushID(label); - - const int components = 2; const float w_full = window->DC.ItemWidth.back(); const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)) / (float)components)); const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1))); + bool value_changed = false; + ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); - value_changed |= ImGui::InputFloat("##X", &v[0], 0, 0, decimal_precision); - ImGui::SameLine(0, 0); - ImGui::PopItemWidth(); - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::InputFloat("##Y", &v[1], 0, 0, decimal_precision); - ImGui::SameLine(0, 0); + for (int i = 0; i < components; i++) + { + ImGui::PushID(i); + if (i + 1 == components) + { + ImGui::PopItemWidth(); + ImGui::PushItemWidth(w_item_last); + } + value_changed |= ImGui::InputFloat("##v", &v[i], 0, 0, decimal_precision); + ImGui::SameLine(0, 0); + ImGui::PopID(); + } ImGui::PopItemWidth(); + ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); - ImGui::PopID(); return value_changed; } -bool InputFloat3(const char* label, float v[3], int decimal_precision) +bool InputFloat2(const char* label, float v[2], int decimal_precision) { - ImGuiState& g = GImGui; - ImGuiWindow* window = GetCurrentWindow(); - if (window->Collapsed) - return false; - - const ImGuiStyle& style = g.Style; - - bool value_changed = false; - ImGui::PushID(label); - - const int components = 3; - const float w_full = window->DC.ItemWidth.back(); - const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)) / (float)components)); - const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1))); - - ImGui::PushItemWidth(w_item_one); - value_changed |= ImGui::InputFloat("##X", &v[0], 0, 0, decimal_precision); - ImGui::SameLine(0, 0); - value_changed |= ImGui::InputFloat("##Y", &v[1], 0, 0, decimal_precision); - ImGui::SameLine(0, 0); - ImGui::PopItemWidth(); - - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::InputFloat("##Z", &v[2], 0, 0, decimal_precision); - ImGui::SameLine(0, 0); - ImGui::PopItemWidth(); + return InputFloatN(label, v, 2, decimal_precision); +} - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); +bool InputFloat3(const char* label, float v[3], int decimal_precision) +{ + return InputFloatN(label, v, 3, decimal_precision); +} - ImGui::PopID(); - return value_changed; +bool InputFloat4(const char* label, float v[4], int decimal_precision) +{ + return InputFloatN(label, v, 4, decimal_precision); } static bool Combo_ArrayGetter(void* data, int idx, const char** out_text) @@ -5585,11 +5550,14 @@ void ShowTestWindow(bool* open) ImGui::InputInt("input int", &i0); ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); - //static float vec2b[3] = { 0.10f, 0.20f }; - //ImGui::InputFloat2("input float2", vec2b); + //static float vec2a[3] = { 0.10f, 0.20f }; + //ImGui::InputFloat2("input float2", vec2a); - static float vec3b[3] = { 0.10f, 0.20f, 0.30f }; - ImGui::InputFloat3("input float3", vec3b); + static float vec3a[3] = { 0.10f, 0.20f, 0.30f }; + ImGui::InputFloat3("input float3", vec3a); + + //static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + //ImGui::InputFloat4("input float4", vec4a); static int i1=0; static int i2=42; @@ -5607,11 +5575,14 @@ void ShowTestWindow(bool* open) static float angle = 0.0f; ImGui::SliderAngle("angle", &angle); - //static float vec2a[3] = { 0.10f, 0.20f }; - //ImGui::SliderFloat2("slider float2", vec2a, 0.0f, 1.0f); + //static float vec2b[3] = { 0.10f, 0.20f }; + //ImGui::SliderFloat2("slider float2", vec2b, 0.0f, 1.0f); - static float vec3a[3] = { 0.10f, 0.20f, 0.30f }; - ImGui::SliderFloat3("slider float3", vec3a, 0.0f, 1.0f); + static float vec3b[3] = { 0.10f, 0.20f, 0.30f }; + ImGui::SliderFloat3("slider float3", vec3b, 0.0f, 1.0f); + + //static float vec4b[4] = { 0.10f, 0.20f, 0.30f, 0.40f }; + //ImGui::SliderFloat4("slider float4", vec4b, 0.0f, 1.0f); static float col1[3] = { 1.0f,0.0f,0.2f }; static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; diff --git a/imgui.h b/imgui.h index 3933c25ac..697100eb0 100644 --- a/imgui.h +++ b/imgui.h @@ -191,6 +191,7 @@ namespace ImGui bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + bool SliderFloat4(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), size_t stride = sizeof(float)); @@ -202,6 +203,7 @@ namespace ImGui bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1); bool InputFloat2(const char* label, float v[2], int decimal_precision = -1); bool InputFloat3(const char* label, float v[3], int decimal_precision = -1); + bool InputFloat4(const char* label, float v[4], int decimal_precision = -1); bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100); bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0); bool Combo(const char* label, int* current_item, const char** items, int items_count, int popup_height_items = 7);