From a908c109c09cbb54962bb5b3a5056c188fe260e7 Mon Sep 17 00:00:00 2001 From: Nikolay Zapolnov Date: Sun, 31 Jan 2016 22:08:35 +0100 Subject: [PATCH 001/400] Added flag for selectables to handle double clicks. --- imgui.cpp | 7 ++++++- imgui.h | 3 ++- imgui_demo.cpp | 7 ++++++- imgui_internal.h | 25 +++++++++++++------------ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8f55e6bf..22300c3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5222,7 +5222,11 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetHoveredID(id); if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { - if (g.IO.MouseClicked[0]) + if (g.IO.MouseDoubleClicked[0] && (flags & ImGuiButtonFlags_PressedOnDoubleClick)) + { + pressed = true; + } + else if (g.IO.MouseClicked[0]) { if (flags & ImGuiButtonFlags_PressedOnClick) { @@ -8135,6 +8139,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick; if (flags & ImGuiSelectableFlags_MenuItem) button_flags |= ImGuiButtonFlags_PressedOnClick|ImGuiButtonFlags_PressedOnRelease; if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; + if (flags & ImGuiSelectableFlags_HandleDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick; bool hovered, held; bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags); if (flags & ImGuiSelectableFlags_Disabled) diff --git a/imgui.h b/imgui.h index a6a249d0..ba3ba9a5 100644 --- a/imgui.h +++ b/imgui.h @@ -504,7 +504,8 @@ enum ImGuiSelectableFlags_ { // Default: 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_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) + ImGuiSelectableFlags_HandleDoubleClick = 1 << 2 // Generate press events on double clicks too }; // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 46883706..26d33ead 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -392,11 +392,16 @@ void ImGui::ShowTestWindow(bool* p_opened) { if (ImGui::TreeNode("Basic")) { - static bool selected[3] = { false, true, false }; + static bool selected[4] = { false, true, false, false }; ImGui::Selectable("1. I am selectable", &selected[0]); ImGui::Selectable("2. I am selectable", &selected[1]); ImGui::Text("3. I am not selectable"); ImGui::Selectable("4. I am selectable", &selected[2]); + if (ImGui::Selectable("5. I am double clickable", selected[3], ImGuiSelectableFlags_HandleDoubleClick)) + { + if (ImGui::IsMouseDoubleClicked(0)) + selected[3] = !selected[3]; + } ImGui::TreePop(); } if (ImGui::TreeNode("Rendering more text into the same block")) diff --git a/imgui_internal.h b/imgui_internal.h index c8748ada..b3c84e66 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -152,14 +152,15 @@ inline void operator delete(void*, ImPlacementNewDummy, void*) {} enum ImGuiButtonFlags_ { - ImGuiButtonFlags_Repeat = 1 << 0, - ImGuiButtonFlags_PressedOnClick = 1 << 1, // return pressed on click only (default requires click+release) - ImGuiButtonFlags_PressedOnRelease = 1 << 2, // return pressed on release only (default requires click+release) - ImGuiButtonFlags_FlattenChilds = 1 << 3, - ImGuiButtonFlags_DontClosePopups = 1 << 4, - ImGuiButtonFlags_Disabled = 1 << 5, - ImGuiButtonFlags_AlignTextBaseLine = 1 << 6, - ImGuiButtonFlags_NoKeyModifiers = 1 << 7 + ImGuiButtonFlags_Repeat = 1 << 0, + ImGuiButtonFlags_PressedOnClick = 1 << 1, // return pressed on click only (default requires click+release) + ImGuiButtonFlags_PressedOnRelease = 1 << 2, // return pressed on release only (default requires click+release) + ImGuiButtonFlags_FlattenChilds = 1 << 3, + ImGuiButtonFlags_DontClosePopups = 1 << 4, + ImGuiButtonFlags_Disabled = 1 << 5, + ImGuiButtonFlags_AlignTextBaseLine = 1 << 6, + ImGuiButtonFlags_NoKeyModifiers = 1 << 7, + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8 }; enum ImGuiTreeNodeFlags_ @@ -176,10 +177,10 @@ enum ImGuiSliderFlags_ enum ImGuiSelectableFlagsPrivate_ { // NB: need to be in sync with last value of ImGuiSelectableFlags_ - ImGuiSelectableFlags_Menu = 1 << 2, - ImGuiSelectableFlags_MenuItem = 1 << 3, - ImGuiSelectableFlags_Disabled = 1 << 4, - ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 5 + ImGuiSelectableFlags_Menu = 1 << 3, + ImGuiSelectableFlags_MenuItem = 1 << 4, + ImGuiSelectableFlags_Disabled = 1 << 5, + ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 6 }; // FIXME: this is in development, not exposed/functional as a generic feature yet. From 4afe67cdc8063e6e4f3b0ec75bef81b9af484443 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Feb 2016 11:50:21 +0100 Subject: [PATCH 002/400] Demo: Fixed malloc/free mismatch and leak when destructing demo console (if it has been used) (#536) --- imgui_demo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f0b460fc..229cd533 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1890,14 +1890,14 @@ struct ExampleAppConsole ~ExampleAppConsole() { ClearLog(); - for (int i = 0; i < Items.Size; i++) + for (int i = 0; i < History.Size; i++) free(History[i]); } // Portable helpers static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } - static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = ImGui::MemAlloc(len); return (char*)memcpy(buff, (const void*)str, len); } + static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); } void ClearLog() { From 1881cbe860f900d3eceb9694c67a3197be301f50 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Feb 2016 22:43:17 +0100 Subject: [PATCH 003/400] TextUnformatted: Fixed rare crash bug with large blurb of text (2k+) not finishing with a '\n' and fully above the clipping Y line. (#535) --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 8617a682..5f54691e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5076,6 +5076,8 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) while (line < text_end && lines_skipped < lines_skippable) { const char* line_end = strchr(line, '\n'); + if (!line_end) + line_end = text_end; line = line_end + 1; lines_skipped++; } From ba80a457b9327ee58c15463a1a4a08c2f05a9852 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Feb 2016 12:53:05 +0100 Subject: [PATCH 004/400] Demo: plot code doesn't use ImVector to avoid heap allocation + comment (#538) --- imgui_demo.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 229cd533..8177a3ee 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -713,7 +713,9 @@ void ImGui::ShowTestWindow(bool* p_opened) static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); - static ImVector values; if (values.empty()) { values.resize(90); memset(values.Data, 0, values.Size*sizeof(float)); } + // Create a dummy array of contiguous float values to plot + // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter. + static float values[90] = { 0 }; static int values_offset = 0; if (animate) { @@ -722,11 +724,11 @@ void ImGui::ShowTestWindow(bool* p_opened) { static float phase = 0.0f; values[values_offset] = cosf(phase); - values_offset = (values_offset+1)%values.Size; + values_offset = (values_offset+1) % IM_ARRAYSIZE(values); phase += 0.10f*values_offset; } } - ImGui::PlotLines("Lines", values.Data, values.Size, values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80)); // Use functions to generate output From 17d3c202ac4cd3c5938beb95031280515eae23ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 2 Mar 2016 21:46:23 +0100 Subject: [PATCH 005/400] BeginChild()/EndChild() fixed incorrect layout to allow widgets submitted after an auto-fit child wnidow (#540) --- imgui.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5f54691e..17ca5984 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3382,12 +3382,11 @@ void ImGui::EndChild() else { // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting. - ImGuiState& g = *GImGui; ImVec2 sz = ImGui::GetWindowSize(); - if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) // Arbitrary minimum zeroish child size of 4.0f - sz.x = ImMax(4.0f, sz.x - g.Style.WindowPadding.x); + if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f + sz.x = ImMax(4.0f, sz.x); if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitY) - sz.y = ImMax(4.0f, sz.y - g.Style.WindowPadding.y); + sz.y = ImMax(4.0f, sz.y); ImGui::End(); From cf12bc7dea3b9db2dbf599ec2ffce430f0965023 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 2 Mar 2016 23:34:29 +0100 Subject: [PATCH 006/400] InputText: Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it. Zero-ing structure properly before use. (#541) --- imgui.cpp | 32 ++++++++++++++++++-------------- imgui.h | 12 +++++++----- imgui_demo.cpp | 4 ++-- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 17ca5984..9cb9bad8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -149,6 +149,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. @@ -7117,41 +7118,41 @@ void ImGuiTextEditState::OnKeyPressed(int key) // Public API to manipulate UTF-8 text // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) +// FIXME: The existence of this rarely exercised code path is a bit of a nuisance. void ImGuiTextEditCallbackData::DeleteChars(int pos, int bytes_count) { + IM_ASSERT(pos + bytes_count <= BufTextLen); char* dst = Buf + pos; const char* src = Buf + pos + bytes_count; while (char c = *src++) *dst++ = c; *dst = '\0'; - BufDirty = true; if (CursorPos + bytes_count >= pos) CursorPos -= bytes_count; else if (CursorPos >= pos) CursorPos = pos; SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen -= bytes_count; } void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) { - const int text_len = (int)strlen(Buf); - if (!new_text_end) - new_text_end = new_text + strlen(new_text); - const int new_text_len = (int)(new_text_end - new_text); - - if (new_text_len + text_len + 1 >= BufSize) + const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); + if (new_text_len + BufTextLen + 1 >= BufSize) return; - if (text_len != pos) - memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(text_len - pos)); + if (BufTextLen != pos) + memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos)); memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); - Buf[text_len + new_text_len] = '\0'; + Buf[BufTextLen + new_text_len] = '\0'; - BufDirty = true; if (CursorPos >= pos) CursorPos += new_text_len; SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen += new_text_len; } // Return false to discard a character. @@ -7543,6 +7544,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (event_key != ImGuiKey_COUNT || (flags & ImGuiInputTextFlags_CallbackAlways) != 0) { ImGuiTextEditCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData)); callback_data.EventFlag = event_flag; callback_data.Flags = flags; callback_data.UserData = user_data; @@ -7550,10 +7552,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 callback_data.EventKey = event_key; callback_data.Buf = edit_state.TempTextBuffer.Data; + callback_data.BufTextLen = edit_state.CurLenA; callback_data.BufSize = edit_state.BufSizeA; callback_data.BufDirty = false; - // We have to convert from position from wchar to UTF-8 positions + // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) ImWchar* text = edit_state.Text.Data; const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor); const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start); @@ -7571,8 +7574,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); if (callback_data.BufDirty) { - edit_state.CurLenW = ImTextStrFromUtf8(text, edit_state.Text.Size, edit_state.TempTextBuffer.Data, NULL); - edit_state.CurLenA = (int)strlen(edit_state.TempTextBuffer.Data); + IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL); + edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() edit_state.CursorAnimReset(); } } diff --git a/imgui.h b/imgui.h index 5abc578b..fe401566 100644 --- a/imgui.h +++ b/imgui.h @@ -944,7 +944,7 @@ struct ImGuiStorage IMGUI_API void SetAllInt(int val); }; -// Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used. +// Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used and the corresponding callback is triggered. struct ImGuiTextEditCallbackData { ImGuiInputTextFlags EventFlag; // One of ImGuiInputTextFlags_Callback* // Read-only @@ -956,15 +956,17 @@ struct ImGuiTextEditCallbackData ImWchar EventChar; // Character input // Read-write (replace character or set to zero) // Completion,History,Always events: + // If you modify the buffer contents make sure you update 'BufTextLen' and set 'BufDirty' to true. ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only - char* Buf; // Current text // Read-write (pointed data only) - int BufSize; // // Read-only - bool BufDirty; // Must set if you modify Buf directly // Write + char* Buf; // Current text buffer // Read-write (pointed data only, can't replace the actual pointer) + int BufTextLen; // Current text length in bytes // Read-write + int BufSize; // Maximum text length in bytes // Read-only + bool BufDirty; // Set if you modify Buf/BufTextLen!! // Write int CursorPos; // // Read-write int SelectionStart; // // Read-write (== to SelectionEnd when no selection) int SelectionEnd; // // Read-write - // NB: calling those function loses selection. + // NB: Helper functions for text manipulation. Calling those function loses selection. void DeleteChars(int pos, int bytes_count); void InsertChars(int pos, const char* text, const char* text_end = NULL); bool HasSelection() const { return SelectionStart != SelectionEnd; } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8177a3ee..043f660f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1888,6 +1888,7 @@ struct ExampleAppConsole Commands.push_back("HISTORY"); Commands.push_back("CLEAR"); Commands.push_back("CLASSIFY"); // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches. + AddLog("Welcome to ImGui!"); } ~ExampleAppConsole() { @@ -2128,9 +2129,8 @@ struct ExampleAppConsole // A better implementation would preserve the data on the current input line along with cursor position. if (prev_history_pos != HistoryPos) { - snprintf(data->Buf, data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : ""); + data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : ""); data->BufDirty = true; - data->CursorPos = data->SelectionStart = data->SelectionEnd = (int)strlen(data->Buf); } } } From d45044fe54bae2b053df3eb5fe4c7c4962b32f06 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 3 Mar 2016 00:09:41 +0100 Subject: [PATCH 007/400] CaptureKeyboardFromApp() / CaptureMouseFromApp(): allow to enforce clearing the capture flag (#533) + demo + made code a little less messy --- imgui.cpp | 23 +++++++++++++---------- imgui.h | 4 ++-- imgui_demo.cpp | 10 +++++++--- imgui_internal.h | 6 +++--- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9cb9bad8..3fd3ebb6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1990,7 +1990,7 @@ void ImGui::NewFrame() } // Are we using inputs? Tell user so they can capture/discard the inputs away from the rest of their application. - // When clicking outside of a window we assume the click is owned by the application and won't request capture. + // When clicking outside of a window we assume the click is owned by the application and won't request capture. We need to track click ownership. int mouse_earliest_button_down = -1; bool mouse_any_down = false; for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) @@ -2002,16 +2002,19 @@ void ImGui::NewFrame() if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[mouse_earliest_button_down] > g.IO.MouseClickedTime[i]) mouse_earliest_button_down = i; } - bool mouse_owned_by_application = mouse_earliest_button_down != -1 && !g.IO.MouseDownOwned[mouse_earliest_button_down]; - g.IO.WantCaptureMouse = (!mouse_owned_by_application && g.HoveredWindow != NULL) || (!mouse_owned_by_application && mouse_any_down) || (g.ActiveId != 0) || (!g.OpenedPopupStack.empty()) || (g.CaptureMouseNextFrame); - g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (g.CaptureKeyboardNextFrame); + bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; + if (g.CaptureMouseNextFrame != -1) + g.IO.WantCaptureMouse = (g.CaptureMouseNextFrame != 0); + else + g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.ActiveId != 0) || (!g.OpenedPopupStack.empty()); + g.IO.WantCaptureKeyboard = (g.CaptureKeyboardNextFrame != -1) ? (g.CaptureKeyboardNextFrame != 0) : (g.ActiveId != 0); g.IO.WantTextInput = (g.ActiveId != 0 && g.InputTextState.Id == g.ActiveId); g.MouseCursor = ImGuiMouseCursor_Arrow; - g.CaptureMouseNextFrame = g.CaptureKeyboardNextFrame = false; + g.CaptureMouseNextFrame = g.CaptureKeyboardNextFrame = -1; g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. - if (mouse_owned_by_application) + if (!mouse_avail_to_imgui) g.HoveredWindow = g.HoveredRootWindow = NULL; // Scale & Scrolling @@ -2990,14 +2993,14 @@ void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) GImGui->MouseCursor = cursor_type; } -void ImGui::CaptureKeyboardFromApp() +void ImGui::CaptureKeyboardFromApp(bool capture) { - GImGui->CaptureKeyboardNextFrame = true; + GImGui->CaptureKeyboardNextFrame = capture ? 1 : 0; } -void ImGui::CaptureMouseFromApp() +void ImGui::CaptureMouseFromApp(bool capture) { - GImGui->CaptureMouseNextFrame = true; + GImGui->CaptureMouseNextFrame = capture ? 1 : 0; } bool ImGui::IsItemHovered() diff --git a/imgui.h b/imgui.h index fe401566..9a0fa054 100644 --- a/imgui.h +++ b/imgui.h @@ -415,8 +415,8 @@ namespace ImGui IMGUI_API void ResetMouseDragDelta(int button = 0); // IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type - IMGUI_API void CaptureKeyboardFromApp(); // manually enforce imgui setting the io.WantCaptureKeyboard flag next frame (your application needs to handle it). e.g. capture keyboard when your widget is being hovered. - IMGUI_API void CaptureMouseFromApp(); // manually enforce imgui setting the io.WantCaptureMouse flag next frame (your application needs to handle it). + IMGUI_API void CaptureKeyboardFromApp(bool capture = true); // manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application handle). e.g. force capture keyboard when your widget is being hovered. + IMGUI_API void CaptureMouseFromApp(bool capture = true); // manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application handle). // Helpers functions to access functions pointers in ImGui::GetIO() IMGUI_API void* MemAlloc(size_t sz); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 043f660f..2135492d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1503,10 +1503,14 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Text("WantCaptureKeyboard: %s", io.WantCaptureKeyboard ? "true" : "false"); ImGui::Text("WantTextInput: %s", io.WantTextInput ? "true" : "false"); - ImGui::Button("Hover me\nto enforce\ninputs capture"); + ImGui::Button("Hovering me sets the\nkeyboard capture flag"); if (ImGui::IsItemHovered()) - ImGui::CaptureKeyboardFromApp(); - + ImGui::CaptureKeyboardFromApp(true); + ImGui::SameLine(); + ImGui::Button("Holding me clears the\nthe keyboard capture flag"); + if (ImGui::IsItemActive()) + ImGui::CaptureKeyboardFromApp(false); + ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index a4caacff..d08d309c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -434,8 +434,8 @@ struct ImGuiState float FramerateSecPerFrame[120]; // calculate estimate of framerate for user int FramerateSecPerFrameIdx; float FramerateSecPerFrameAccum; - bool CaptureMouseNextFrame; // explicit capture via CaptureInputs() sets those flags - bool CaptureKeyboardNextFrame; + int CaptureMouseNextFrame; // explicit capture via CaptureInputs() sets those flags + int CaptureKeyboardNextFrame; char TempBuffer[1024*3+1]; // temporary text buffer ImGuiState() @@ -501,7 +501,7 @@ struct ImGuiState memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); FramerateSecPerFrameIdx = 0; FramerateSecPerFrameAccum = 0.0f; - CaptureMouseNextFrame = CaptureKeyboardNextFrame = false; + CaptureMouseNextFrame = CaptureKeyboardNextFrame = -1; memset(TempBuffer, 0, sizeof(TempBuffer)); } }; From b816d05e337f6bfbf05ec98702c5f11356b00ff6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 3 Mar 2016 00:30:08 +0100 Subject: [PATCH 008/400] Minor tidying up following (#516) - renamed ImGuiSelectableFlags_HandleDoubleClick to ImGuiSelectableFlags_AllowDoubleClick + comments --- imgui.cpp | 2 +- imgui.h | 2 +- imgui_demo.cpp | 4 +--- imgui_internal.h | 18 +++++++++--------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8e8ab2b6..50b0219a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8147,7 +8147,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick; if (flags & ImGuiSelectableFlags_MenuItem) button_flags |= ImGuiButtonFlags_PressedOnClick|ImGuiButtonFlags_PressedOnRelease; if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; - if (flags & ImGuiSelectableFlags_HandleDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick; + if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick; bool hovered, held; bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags); if (flags & ImGuiSelectableFlags_Disabled) diff --git a/imgui.h b/imgui.h index 27a8ce95..57a7f797 100644 --- a/imgui.h +++ b/imgui.h @@ -506,7 +506,7 @@ enum ImGuiSelectableFlags_ // Default: 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_HandleDoubleClick = 1 << 2 // Generate press events on double clicks too + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2 // Generate press events on double clicks too }; // User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 47e97526..b2e4e09e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -397,11 +397,9 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Selectable("2. I am selectable", &selected[1]); ImGui::Text("3. I am not selectable"); ImGui::Selectable("4. I am selectable", &selected[2]); - if (ImGui::Selectable("5. I am double clickable", selected[3], ImGuiSelectableFlags_HandleDoubleClick)) - { + if (ImGui::Selectable("5. I am double clickable", selected[3], ImGuiSelectableFlags_AllowDoubleClick)) if (ImGui::IsMouseDoubleClicked(0)) selected[3] = !selected[3]; - } ImGui::TreePop(); } if (ImGui::TreeNode("Rendering more text into the same block")) diff --git a/imgui_internal.h b/imgui_internal.h index 51d97093..eaeb312e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -152,15 +152,15 @@ inline void operator delete(void*, ImPlacementNewDummy, void*) {} enum ImGuiButtonFlags_ { - ImGuiButtonFlags_Repeat = 1 << 0, - ImGuiButtonFlags_PressedOnClick = 1 << 1, // return pressed on click only (default requires click+release) - ImGuiButtonFlags_PressedOnRelease = 1 << 2, // return pressed on release only (default requires click+release) - ImGuiButtonFlags_FlattenChilds = 1 << 3, - ImGuiButtonFlags_DontClosePopups = 1 << 4, - ImGuiButtonFlags_Disabled = 1 << 5, - ImGuiButtonFlags_AlignTextBaseLine = 1 << 6, - ImGuiButtonFlags_NoKeyModifiers = 1 << 7, - ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8 + ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat + ImGuiButtonFlags_PressedOnClick = 1 << 1, // return pressed on click (default requires click+release) + ImGuiButtonFlags_PressedOnRelease = 1 << 2, // return pressed on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 3, // return pressed on double-click (default requires click+release) + ImGuiButtonFlags_FlattenChilds = 1 << 4, // allow interaction even if a child window is overlapping + ImGuiButtonFlags_DontClosePopups = 1 << 5, // disable automatically closing parent popup on press + ImGuiButtonFlags_Disabled = 1 << 6, // disable interaction + ImGuiButtonFlags_AlignTextBaseLine = 1 << 7, // vertically align button to match text baseline - ButtonEx() only + ImGuiButtonFlags_NoKeyModifiers = 1 << 8, // disable interaction if a key modifier is held }; enum ImGuiTreeNodeFlags_ From 2065cbec4dc949a8a3f55fba0fc25d7ed342036d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 3 Mar 2016 00:34:06 +0100 Subject: [PATCH 009/400] Removed extraneous comma for pedantic compilers (#516) --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index eaeb312e..f6300e74 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -160,7 +160,7 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_DontClosePopups = 1 << 5, // disable automatically closing parent popup on press ImGuiButtonFlags_Disabled = 1 << 6, // disable interaction ImGuiButtonFlags_AlignTextBaseLine = 1 << 7, // vertically align button to match text baseline - ButtonEx() only - ImGuiButtonFlags_NoKeyModifiers = 1 << 8, // disable interaction if a key modifier is held + ImGuiButtonFlags_NoKeyModifiers = 1 << 8 // disable interaction if a key modifier is held }; enum ImGuiTreeNodeFlags_ From 3db40903bab9b01bf5855f5d929270c41a822e6b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 4 Mar 2016 13:07:42 +0100 Subject: [PATCH 010/400] InputText() ImGuiInputTextFlags_CallbackAlways event set the EventFlag field of ImGuiTextEditCallbackData (#541) --- imgui.cpp | 5 ++++- imgui.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 50b0219a..746ff749 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -437,6 +437,7 @@ - main: IsItemHovered() make it 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: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) + - input text: reorganise event handling, allow CharFilter to modify buffers, allow multiple events? (#541) - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200) - input text multi-line: line numbers? status bar? (follow up on #200) @@ -7547,8 +7548,10 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 event_flag = ImGuiInputTextFlags_CallbackHistory; event_key = ImGuiKey_DownArrow; } + else if (flags & ImGuiInputTextFlags_CallbackAlways) + event_flag = ImGuiInputTextFlags_CallbackAlways; - if (event_key != ImGuiKey_COUNT || (flags & ImGuiInputTextFlags_CallbackAlways) != 0) + if (event_flag) { ImGuiTextEditCallbackData callback_data; memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData)); diff --git a/imgui.h b/imgui.h index 57a7f797..43e6ab3b 100644 --- a/imgui.h +++ b/imgui.h @@ -488,7 +488,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to when the value was modified) ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Call user function on pressing TAB (for completion handling) ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Call user function on pressing Up/Down arrows (for history handling) - ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Call user function every time + ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Call user function every time. User code may query cursor position, modify text buffer. ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Call user function to filter character. Modify data->EventChar to replace/filter input, or return 1 to discard character. ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, allow exiting edition by pressing Enter. Ctrl+Enter to add new line (by default adds new lines with Enter). From 63466909629570ec7067eca4ddf8c1c54cf9fd7b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 4 Mar 2016 14:09:08 +0100 Subject: [PATCH 011/400] Comment (#544) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 43e6ab3b..2c111949 100644 --- a/imgui.h +++ b/imgui.h @@ -1256,7 +1256,7 @@ struct ImFontAtlas int TexHeight; // Texture height calculated during Build(). int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block) - ImVector Fonts; + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. // Private ImVector ConfigData; // Internal data From 1dcb9c877d2a591587bc581130d9f95c36e374ca Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Mar 2016 10:46:57 +0100 Subject: [PATCH 012/400] Examples: OpenGL: Fix early return on zero-sized framebuffer breaking GL state (#486, #547) --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 16 ++++++++-------- examples/opengl_example/imgui_impl_glfw.cpp | 16 ++++++++-------- .../sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 16 ++++++++-------- examples/sdl_opengl_example/imgui_impl_sdl.cpp | 16 ++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index e62f1a64..fe895fb0 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -33,6 +33,14 @@ static unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0; // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) { + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + ImGuiIO& io = ImGui::GetIO(); + int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); + int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); + if (fb_width == 0 || fb_height == 0) + return; + draw_data->ScaleClipRects(io.DisplayFramebufferScale); + // Backup GL state GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); @@ -58,14 +66,6 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) glEnable(GL_SCISSOR_TEST); glActiveTexture(GL_TEXTURE0); - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) - ImGuiIO& io = ImGui::GetIO(); - int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); - int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); - if (fb_width == 0 || fb_height == 0) - return; - draw_data->ScaleClipRects(io.DisplayFramebufferScale); - // Setup viewport, orthographic projection matrix glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); const float ortho_projection[4][4] = diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 267b6803..54943e1d 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -28,6 +28,14 @@ static GLuint g_FontTexture = 0; // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) { + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + ImGuiIO& io = ImGui::GetIO(); + int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); + int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); + if (fb_width == 0 || fb_height == 0) + return; + draw_data->ScaleClipRects(io.DisplayFramebufferScale); + // We are using the OpenGL fixed pipeline to make the example code simpler to read! // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); @@ -44,14 +52,6 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) glEnable(GL_TEXTURE_2D); //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) - ImGuiIO& io = ImGui::GetIO(); - int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); - int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); - if (fb_width == 0 || fb_height == 0) - return; - draw_data->ScaleClipRects(io.DisplayFramebufferScale); - // Setup viewport, orthographic projection matrix glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); glMatrixMode(GL_PROJECTION); diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index d4cecb13..accaa60a 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -28,6 +28,14 @@ static unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0; // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) { + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + ImGuiIO& io = ImGui::GetIO(); + int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); + int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); + if (fb_width == 0 || fb_height == 0) + return; + draw_data->ScaleClipRects(io.DisplayFramebufferScale); + // Backup GL state GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); @@ -53,14 +61,6 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) glEnable(GL_SCISSOR_TEST); glActiveTexture(GL_TEXTURE0); - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) - ImGuiIO& io = ImGui::GetIO(); - int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); - int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); - if (fb_width == 0 || fb_height == 0) - return; - draw_data->ScaleClipRects(io.DisplayFramebufferScale); - // Setup orthographic projection matrix glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); const float ortho_projection[4][4] = diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index 6ace60a0..a8429a25 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -21,6 +21,14 @@ static GLuint g_FontTexture = 0; // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) { + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + ImGuiIO& io = ImGui::GetIO(); + int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); + int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); + if (fb_width == 0 || fb_height == 0) + return; + draw_data->ScaleClipRects(io.DisplayFramebufferScale); + // We are using the OpenGL fixed pipeline to make the example code simpler to read! // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); @@ -37,14 +45,6 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) glEnable(GL_TEXTURE_2D); //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) - ImGuiIO& io = ImGui::GetIO(); - int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); - int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); - if (fb_width == 0 || fb_height == 0) - return; - draw_data->ScaleClipRects(io.DisplayFramebufferScale); - // Setup viewport, orthographic projection matrix glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); glMatrixMode(GL_PROJECTION); From 9ea093ddd0c0ef9523d0918099f1a3a59eb6a42b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Mar 2016 13:12:15 +0100 Subject: [PATCH 013/400] DragFloat(): always apply value when mouse is held/widget active, so that can use a drag over an always-reseting value --- imgui.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 746ff749..91abb338 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6413,6 +6413,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s g.DragLastMouseDelta = ImVec2(0.f, 0.f); } + float v_cur = g.DragCurrentValue; const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f); if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f) { @@ -6424,7 +6425,6 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f) speed = speed * g.DragSpeedScaleSlow; - float v_cur = g.DragCurrentValue; float delta = (mouse_drag_delta.x - g.DragLastMouseDelta.x) * speed; if (fabsf(power - 1.0f) > 0.001f) { @@ -6446,14 +6446,14 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s if (v_min < v_max) v_cur = ImClamp(v_cur, v_min, v_max); g.DragCurrentValue = v_cur; + } - // Round to user desired precision, then apply - v_cur = RoundScalar(v_cur, decimal_precision); - if (*v != v_cur) - { - *v = v_cur; - value_changed = true; - } + // Round to user desired precision, then apply + v_cur = RoundScalar(v_cur, decimal_precision); + if (*v != v_cur) + { + *v = v_cur; + value_changed = true; } } else From 4b7edffe8a67dc30d22bdc284b208aa01b4f3461 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 8 Mar 2016 20:54:21 +0100 Subject: [PATCH 014/400] Comments --- imgui.cpp | 11 +++++++++-- imgui.h | 6 +++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 91abb338..c50a894e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -19,7 +19,7 @@ - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS - How can I help? - How do I update to a newer version of ImGui? - - Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) + - Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) / A primer on the use of labels/IDs in ImGui. - I integrated ImGui in my engine and the text or lines are blurry.. - I integrated ImGui in my engine and some elements are disappearing when I move windows around.. - How can I load a different font than the default? @@ -426,6 +426,7 @@ - window: detect extra End() call that pop the "Debug" window out and assert at call site instead of later. - window: consider renaming "GetWindowFont" which conflict with old Windows #define (#340) - window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic. + - window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd. - draw-list: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). !- scrolling: allow immediately effective change of scroll if we haven't appended items yet - splitter/separator: formalize the splitter idiom into an official api (we want to handle n-way split) (#319) @@ -437,7 +438,7 @@ - main: IsItemHovered() make it 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: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) - - input text: reorganise event handling, allow CharFilter to modify buffers, allow multiple events? (#541) + - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200) - input text multi-line: line numbers? status bar? (follow up on #200) @@ -445,6 +446,7 @@ - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: use mouse wheel to step up/down - input number: applying arithmetics ops (+,-,*,/) messes up with text edit undo stack. + - button: provide a button that looks framed. - text: proper alignment options - image/image button: misalignment on padded/bordered button? - image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that? @@ -452,6 +454,7 @@ - layout: horizontal flow until no space left (#404) - layout: more generic alignment state (left/right/centered) for single items? - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding. + - layout: BeginGroup() needs a border option. - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) (#513, #125) - columns: add a conditional parameter to SetColumnOffset() (#513, #125) - columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (#125) @@ -469,9 +472,11 @@ !- popups/menus: clarify usage of popups id, how MenuItem/Selectable closing parent popups affects the ID, etc. this is quite fishy needs improvement! (#331, #402) - popups: add variant using global identifier similar to Begin/End (#402) - popups: border options. richer api like BeginChild() perhaps? (#197) + - tooltip: tooltip that doesn't fit in entire screen seems to lose their "last prefered button" and may teleport when moving mouse - menus: local shortcuts, global shortcuts (#456, #126) - menus: icons - menus: menubars: some sort of priority / effect of main menu-bar on desktop size? + - menus: calling BeginMenu() twice with a same name doesn't seem to append nicely - statusbar: add a per-window status bar helper similar to what menubar does. - tabs (#261, #351) - separator: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y) @@ -495,6 +500,7 @@ - text edit: flag to disable live update of the user buffer. - text edit: field resize behavior - field could stretch when being edited? hover tooltip shows more text? - tree node / optimization: avoid formatting when clipped. + - tree node: clarify spacing, perhaps provide API to query exact spacing. provide API to draw the primitive. same with Bullet(). - tree node: tree-node/header right-most side doesn't take account of horizontal scrolling. - tree node: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings - tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer) @@ -525,6 +531,7 @@ - input: support track pad style scrolling & slider edit. - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? + - misc: provide HoveredTime and ActivatedTime to ease the creation of animations. - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438) - style editor: color child window height expressed in multiple of line height. - remote: make a system like RemoteImGui first-class citizen/project (#75) diff --git a/imgui.h b/imgui.h index 2c111949..5259a789 100644 --- a/imgui.h +++ b/imgui.h @@ -239,7 +239,7 @@ namespace ImGui IMGUI_API 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, recommended for long chunks of text IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_PRINTFARGS(2); // display text+label aligned the same way as value+label widgets IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args); - IMGUI_API void Bullet(); + IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance you by the same distance as an empty TreeNode() call. IMGUI_API void BulletText(const char* fmt, ...) IM_PRINTFARGS(1); IMGUI_API void BulletTextV(const char* fmt, va_list args); IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); @@ -303,8 +303,8 @@ namespace ImGui IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); // Widgets: Trees - IMGUI_API bool TreeNode(const char* str_label_id); // if returning 'true' the node is open and the user is responsible for calling TreePop() - IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_PRINTFARGS(2); // " + IMGUI_API bool TreeNode(const char* str_label_id); // if returning 'true' the node is open and the user is responsible for calling TreePop(). + IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_PRINTFARGS(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(). IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_PRINTFARGS(2); // " IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args); // " IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args); // " From 4cbd316f0183600222625a9da46ab4786bfe2981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Wed, 9 Mar 2016 16:39:54 +0100 Subject: [PATCH 015/400] Vulkan example. --- examples/vulkan_example/CMakeLists.txt | 36 + examples/vulkan_example/gen_spv.sh | 4 + examples/vulkan_example/glsl_shader.frag | 14 + examples/vulkan_example/glsl_shader.vert | 21 + .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 1017 +++++++++++++++++ .../vulkan_example/imgui_impl_glfw_vulkan.h | 41 + examples/vulkan_example/main.cpp | 533 +++++++++ 7 files changed, 1666 insertions(+) create mode 100644 examples/vulkan_example/CMakeLists.txt create mode 100755 examples/vulkan_example/gen_spv.sh create mode 100644 examples/vulkan_example/glsl_shader.frag create mode 100644 examples/vulkan_example/glsl_shader.vert create mode 100644 examples/vulkan_example/imgui_impl_glfw_vulkan.cpp create mode 100644 examples/vulkan_example/imgui_impl_glfw_vulkan.h create mode 100644 examples/vulkan_example/main.cpp diff --git a/examples/vulkan_example/CMakeLists.txt b/examples/vulkan_example/CMakeLists.txt new file mode 100644 index 00000000..daa7a171 --- /dev/null +++ b/examples/vulkan_example/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8) +project(ImGuiGLFWVulkanExample C CXX) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) +endif() + +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES") + +# GLFW +set(GLFW_DIR ../../../glfw) +option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) +option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) +option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) +option(GLFW_INSTALL "Generate installation target" OFF) +option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF) +add_subdirectory(${GLFW_DIR} binary_dir EXCLUDE_FROM_ALL) +include_directories(${GLFW_DIR}/include) + +# ImGui +set(IMGUI_DIR ../../) +include_directories(${IMGUI_DIR}) + +# Libraries +if(WIN32) + set(LIBRARIES "glfw;vulkan-${MAJOR}") +elseif(UNIX) + set(LIBRARIES "glfw;vulkan") +else() +endif() + +file(GLOB sources *.cpp) + +add_executable(vulkan_example ${sources} ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp) +target_link_libraries(vulkan_example ${LIBRARIES}) diff --git a/examples/vulkan_example/gen_spv.sh b/examples/vulkan_example/gen_spv.sh new file mode 100755 index 00000000..f95f8fa8 --- /dev/null +++ b/examples/vulkan_example/gen_spv.sh @@ -0,0 +1,4 @@ +#!/bin/bash +glslangValidator -V -o glsl_shader.frag.spv glsl_shader.frag +glslangValidator -V -o glsl_shader.vert.spv glsl_shader.vert +spirv-remap --map all --dce all --strip-all --input glsl_shader.frag.spv glsl_shader.vert.spv --output ./ diff --git a/examples/vulkan_example/glsl_shader.frag b/examples/vulkan_example/glsl_shader.frag new file mode 100644 index 00000000..8205b673 --- /dev/null +++ b/examples/vulkan_example/glsl_shader.frag @@ -0,0 +1,14 @@ +#version 450 core +layout(location = 0, index = 0) out vec4 fColor; + +layout(set=0, binding=0) uniform sampler2D sTexture; + +in block{ + vec4 Color; + vec2 UV; +} In; + +void main() +{ + fColor = In.Color * texture(sTexture, In.UV.st); +} diff --git a/examples/vulkan_example/glsl_shader.vert b/examples/vulkan_example/glsl_shader.vert new file mode 100644 index 00000000..55098fec --- /dev/null +++ b/examples/vulkan_example/glsl_shader.vert @@ -0,0 +1,21 @@ +#version 450 core +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aUV; +layout(location = 2) in vec4 aColor; + +layout(push_constant) uniform uPushConstant{ + vec2 uScale; + vec2 uTranslate; +} pc; + +out block{ + vec4 Color; + vec2 UV; +} Out; + +void main() +{ + Out.Color = aColor; + Out.UV = aUV; + gl_Position = vec4(aPos*pc.uScale+pc.uTranslate, 0, 1); +} diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp new file mode 100644 index 00000000..7ca1ab9f --- /dev/null +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -0,0 +1,1017 @@ +// ImGui GLFW binding with Vulkan + shaders +// 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 5 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXX_CreateFontsTexture(), ImGui_ImplXXXX_NewFrame(), ImGui_ImplXXXX_Render() and ImGui_ImplXXXX_Shutdown(). +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +#include + +// GLFW +#define GLFW_INCLUDE_NONE +#define GLFW_INCLUDE_VULKAN +#include +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif + +#include "imgui_impl_glfw_vulkan.h" + +// GLFW Data +static GLFWwindow* g_Window = NULL; +static double g_Time = 0.0f; +static bool g_MousePressed[3] = { false, false, false }; +static float g_MouseWheel = 0.0f; + +// Vulkan Data +static VkAllocationCallbacks* g_Allocator = NULL; +static VkPhysicalDevice g_Gpu = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static VkRenderPass g_RenderPass = VK_NULL_HANDLE; +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; +static void (*g_CheckVkResult)(VkResult err) = NULL; + +static VkCommandBuffer g_CommandBuffer = VK_NULL_HANDLE; +static size_t g_BufferMemoryAlignment = 256; +static VkPipelineCreateFlags g_PipelineCreateFlags = 0; +static int g_FrameIndex = 0; + +static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE; +static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE; +static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE; +static VkPipeline g_Pipeline = VK_NULL_HANDLE; + +static VkSampler g_FontSampler = VK_NULL_HANDLE; +static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE; +static VkImage g_FontImage = VK_NULL_HANDLE; +static VkImageView g_FontView = VK_NULL_HANDLE; + +static VkDeviceMemory g_VertexBufferMemory[IMGUI_VK_QUEUED_FRAMES] = {}; +static VkDeviceMemory g_IndexBufferMemory[IMGUI_VK_QUEUED_FRAMES] = {}; +static size_t g_VertexBufferSize[IMGUI_VK_QUEUED_FRAMES] = {}; +static size_t g_IndexBufferSize[IMGUI_VK_QUEUED_FRAMES] = {}; +static VkBuffer g_VertexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; +static VkBuffer g_IndexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; + +static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; +static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; + +static unsigned char __glsl_shader_vert_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x6c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, + 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x16, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x41, 0x14, 0x00, 0x00, + 0x6a, 0x16, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, 0x80, 0x14, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x41, 0x14, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6a, 0x16, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0xb1, 0x02, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0xb1, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0xb1, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0xb1, 0x02, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x80, 0x14, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x06, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x06, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0xfa, 0x16, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x03, 0x00, 0x02, 0x05, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, + 0x1a, 0x04, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1a, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, + 0x47, 0x11, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x9a, 0x02, 0x00, 0x00, 0x41, 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x9b, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0e, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x90, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, 0x6a, 0x16, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x91, 0x02, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x7f, 0x02, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, + 0xb1, 0x02, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x7f, 0x02, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x2e, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x05, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, + 0x80, 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, + 0x06, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x83, 0x06, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x06, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x83, 0x06, 0x00, 0x00, + 0xfa, 0x16, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x92, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x36, 0x00, 0x05, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x1f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x05, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x6b, 0x60, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x71, 0x4e, 0x00, 0x00, + 0x41, 0x14, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x9b, 0x02, 0x00, 0x00, + 0xaa, 0x26, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0xaa, 0x26, 0x00, 0x00, 0x71, 0x4e, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xda, 0x35, 0x00, 0x00, + 0x6a, 0x16, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x91, 0x02, 0x00, 0x00, + 0xea, 0x50, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0xea, 0x50, 0x00, 0x00, 0xda, 0x35, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xc7, 0x35, 0x00, 0x00, + 0x80, 0x14, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x92, 0x02, 0x00, 0x00, + 0xef, 0x56, 0x00, 0x00, 0xfa, 0x16, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xe0, 0x29, 0x00, 0x00, + 0xef, 0x56, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, + 0xa0, 0x22, 0x00, 0x00, 0xc7, 0x35, 0x00, 0x00, 0xe0, 0x29, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x92, 0x02, 0x00, 0x00, 0x42, 0x2c, 0x00, 0x00, + 0xfa, 0x16, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x42, 0x2c, 0x00, 0x00, + 0x81, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, + 0xa0, 0x22, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0xa1, 0x41, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x84, 0x36, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x07, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x47, 0x00, 0x00, + 0xa1, 0x41, 0x00, 0x00, 0x84, 0x36, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x9b, 0x02, 0x00, 0x00, + 0x17, 0x2f, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x17, 0x2f, 0x00, 0x00, 0x54, 0x47, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; +static unsigned int __glsl_shader_vert_spv_len = 1172; + +static unsigned char __glsl_shader_frag_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x6c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1f, 0x16, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x7a, 0x0c, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x1f, 0x16, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x7a, 0x0c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x7a, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1a, 0x04, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xec, 0x14, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0xec, 0x14, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x02, 0x05, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, + 0x7a, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x04, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x97, 0x06, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x9b, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0x96, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x03, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x7b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x7b, 0x04, 0x00, 0x00, + 0xec, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x6b, 0x5d, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x9b, 0x02, 0x00, 0x00, 0x8d, 0x1b, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, + 0x0b, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x0b, 0x40, 0x00, 0x00, 0x8d, 0x1b, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0xfe, 0x01, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00, 0xec, 0x14, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x90, 0x02, 0x00, 0x00, 0xc2, 0x43, 0x00, 0x00, + 0x35, 0x16, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0xc2, 0x43, 0x00, 0x00, + 0x57, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xb9, 0x46, 0x00, 0x00, + 0xc0, 0x36, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0xe4, 0x23, 0x00, 0x00, 0x0b, 0x40, 0x00, 0x00, + 0xb9, 0x46, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7a, 0x0c, 0x00, 0x00, + 0xe4, 0x23, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; +static unsigned int __glsl_shader_frag_spv_len = 660; + +static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) +{ + VkPhysicalDeviceMemoryProperties prop; + vkGetPhysicalDeviceMemoryProperties(g_Gpu, &prop); + for(uint32_t i=0; i < prop.memoryTypeCount; ++i) + if((prop.memoryTypes[i].propertyFlags & properties) == properties && + type_bits & (1<TotalVtxCount * sizeof(ImDrawVert); + if(!g_VertexBuffer[g_FrameIndex] || + g_VertexBufferSize[g_FrameIndex] < vertex_size){ + if(g_VertexBuffer[g_FrameIndex]) + vkDestroyBuffer(g_Device, g_VertexBuffer[g_FrameIndex], g_Allocator); + if(g_VertexBufferMemory[g_FrameIndex]) + vkFreeMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], g_Allocator); + size_t vertex_buffer_size = ((vertex_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = vertex_buffer_size; + buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(g_Device, + &buffer_info, + g_Allocator, + &g_VertexBuffer[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(g_Device, g_VertexBuffer[g_FrameIndex], &req); + g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_VertexBufferMemory[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindBufferMemory(g_Device, + g_VertexBuffer[g_FrameIndex], + g_VertexBufferMemory[g_FrameIndex], 0); + ImGui_ImplGlfwVulkan_VkResult(err); + g_VertexBufferSize[g_FrameIndex] = vertex_buffer_size; + } + // Create the Index Buffer: + size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); + if(!g_IndexBuffer[g_FrameIndex] || + g_IndexBufferSize[g_FrameIndex] < index_size){ + if(g_IndexBuffer[g_FrameIndex]) + vkDestroyBuffer(g_Device, g_IndexBuffer[g_FrameIndex], g_Allocator); + if(g_IndexBufferMemory[g_FrameIndex]) + vkFreeMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], g_Allocator); + size_t index_buffer_size = ((index_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = index_buffer_size; + buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(g_Device, + &buffer_info, + g_Allocator, + &g_IndexBuffer[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(g_Device, g_IndexBuffer[g_FrameIndex], &req); + g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_IndexBufferMemory[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindBufferMemory(g_Device, + g_IndexBuffer[g_FrameIndex], + g_IndexBufferMemory[g_FrameIndex], 0); + ImGui_ImplGlfwVulkan_VkResult(err); + g_IndexBufferSize[g_FrameIndex] = index_buffer_size; + } + // Upload Vertex and index Data: + { + ImDrawVert* vtx_dst; + ImDrawIdx* idx_dst; + err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], + 0, vertex_size, 0, + reinterpret_cast(&vtx_dst)); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], + 0, index_size, 0, + reinterpret_cast(&idx_dst)); + ImGui_ImplGlfwVulkan_VkResult(err); + for(int n = 0; n < draw_data->CmdListsCount; n++){ + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, &cmd_list->VtxBuffer[0], + cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); + memcpy(idx_dst, &cmd_list->IdxBuffer[0], + cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.size(); + idx_dst += cmd_list->IdxBuffer.size(); + } + VkMappedMemoryRange range[2] = {}; + range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[0].memory = g_VertexBufferMemory[g_FrameIndex]; + range[0].size = vertex_size; + range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[1].memory = g_IndexBufferMemory[g_FrameIndex]; + range[1].size = index_size; + err = vkFlushMappedMemoryRanges(g_Device, 2, range); + ImGui_ImplGlfwVulkan_VkResult(err); + vkUnmapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex]); + vkUnmapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex]); + } + // Bind pipeline and descriptor sets: + { + vkCmdBindPipeline(g_CommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + g_Pipeline); + VkDescriptorSet desc_set[1] = {g_DescriptorSet}; + vkCmdBindDescriptorSets(g_CommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + g_PipelineLayout, + 0, 1, desc_set, + 0, NULL); + } + // Bind Vertex And Index Buffer: + { + VkBuffer vertex_buffers[1] = {g_VertexBuffer[g_FrameIndex]}; + VkDeviceSize vertex_offset[1] = {0}; + vkCmdBindVertexBuffers(g_CommandBuffer, + 0, 1, + vertex_buffers, vertex_offset); + vkCmdBindIndexBuffer(g_CommandBuffer, + g_IndexBuffer[g_FrameIndex], + 0, VK_INDEX_TYPE_UINT16); + } + // Setup viewport: + { + VkViewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = ImGui::GetIO().DisplaySize.x; + viewport.height = ImGui::GetIO().DisplaySize.y; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(g_CommandBuffer, 0, 1, &viewport); + } + // Setup scale and translation: + { + float scale[2]; + scale[0] = 2.0f/io.DisplaySize.x; + scale[1] = 2.0f/io.DisplaySize.y; + float translate[2]; + translate[0] = -1.0f; + translate[1] = -1.0f; + vkCmdPushConstants(g_CommandBuffer, + g_PipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT, + sizeof(float) * 0, + sizeof(float) * 2, + scale); + vkCmdPushConstants(g_CommandBuffer, + g_PipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT, + sizeof(float) * 2, + sizeof(float) * 2, + translate); + } + // Render the command lists: + int vtx_offset = 0; + int idx_offset = 0; + for(int n = 0; n < draw_data->CmdListsCount; n++){ + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for(int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++){ + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if(pcmd->UserCallback){ + pcmd->UserCallback(cmd_list, pcmd); + } + else{ + VkRect2D scissor; + scissor.offset.x = static_cast(pcmd->ClipRect.x); + scissor.offset.y = static_cast(pcmd->ClipRect.y); + scissor.extent.width = static_cast(pcmd->ClipRect.z - pcmd->ClipRect.x); + scissor.extent.height = static_cast(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? + vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); + vkCmdDrawIndexed(g_CommandBuffer, + pcmd->ElemCount, 1, + idx_offset, vtx_offset, 0); + } + idx_offset += pcmd->ElemCount; + } + vtx_offset += cmd_list->VtxBuffer.size(); + } +} + +static const char* ImGui_ImplGlfwVulkan_GetClipboardText() +{ + return glfwGetClipboardString(g_Window); +} + +static void ImGui_ImplGlfwVulkan_SetClipboardText(const char* text) +{ + glfwSetClipboardString(g_Window, text); +} + +void ImGui_ImplGlfwVulkan_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) +{ + if (action == GLFW_PRESS && button >= 0 && button < 3) + g_MousePressed[button] = true; +} + +void ImGui_ImplGlfwVulkan_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) +{ + g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. +} + +void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow*, int key, int, int action, int mods) +{ + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + + (void)mods; // Modifiers are not reliable across systems + io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; + io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; + io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; +} + +void ImGui_ImplGlfwVulkan_CharCallback(GLFWwindow*, unsigned int c) +{ + ImGuiIO& io = ImGui::GetIO(); + if (c > 0 && c < 0x10000) + io.AddInputCharacter((unsigned short)c); +} + +bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) +{ + ImGuiIO& io = ImGui::GetIO(); + + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + size_t upload_size = width*height*4*sizeof(char); + + VkResult err; + // Create the Image: + { + VkImageCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + info.imageType = VK_IMAGE_TYPE_2D; + info.format = VK_FORMAT_R8G8B8A8_UNORM; + info.extent.width = width; + info.extent.height = height; + info.extent.depth = 1; + info.mipLevels = 1; + info.arrayLayers = 1; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + err = vkCreateImage(g_Device, + &info, + g_Allocator, + &g_FontImage); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetImageMemoryRequirements(g_Device, g_FontImage, &req); + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_FontMemory); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0); + ImGui_ImplGlfwVulkan_VkResult(err); + } + // Create the Image View: + { + VkResult err; + VkImageViewCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + info.image = g_FontImage; + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + info.format = VK_FORMAT_R8G8B8A8_UNORM; + info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + info.subresourceRange.levelCount = 1; + info.subresourceRange.layerCount = 1; + err = vkCreateImageView(g_Device, + &info, + g_Allocator, + &g_FontView); + ImGui_ImplGlfwVulkan_VkResult(err); + } + // Update the Descriptor Set: + { + VkDescriptorImageInfo desc_image[1] = {}; + desc_image[0].sampler = g_FontSampler; + desc_image[0].imageView = g_FontView; + desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkWriteDescriptorSet write_desc[1] = {}; + write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_desc[0].dstSet = g_DescriptorSet; + write_desc[0].descriptorCount = 1; + write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_desc[0].pImageInfo = desc_image; + vkUpdateDescriptorSets(g_Device, + 1, write_desc, + 0, NULL); + } + // Create the Upload Buffer: + { + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = upload_size; + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(g_Device, + &buffer_info, + g_Allocator, + &g_UploadBuffer); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req); + g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_UploadBufferMemory); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0); + ImGui_ImplGlfwVulkan_VkResult(err); + } + // Upload to Buffer: + { + char *map; + err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, + reinterpret_cast(&map)); + ImGui_ImplGlfwVulkan_VkResult(err); + memcpy(map, pixels, upload_size); + VkMappedMemoryRange range[1] = {}; + range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[0].memory = g_UploadBufferMemory; + range[0].size = upload_size; + err = vkFlushMappedMemoryRanges(g_Device, 1, range); + ImGui_ImplGlfwVulkan_VkResult(err); + vkUnmapMemory(g_Device, g_UploadBufferMemory); + } + // Upload Barrier: + { + VkBufferMemoryBarrier buffer_barrier[1] = {}; + buffer_barrier[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + buffer_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + buffer_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + buffer_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_barrier[0].buffer = g_UploadBuffer; + buffer_barrier[0].size = upload_size; + VkImageMemoryBarrier image_barrier[1] = {}; + image_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].image = g_FontImage; + image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barrier[0].subresourceRange.levelCount = 1; + image_barrier[0].subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(command_buffer, + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, NULL, 1, buffer_barrier, 1, image_barrier); + } + // Copy to Image: + { + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.width = width; + region.imageExtent.height = height; + vkCmdCopyBufferToImage(command_buffer, + g_UploadBuffer, + g_FontImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion); + } + // Usage Barrier: + { + VkImageMemoryBarrier image_barrier[1] = {}; + image_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].image = g_FontImage; + image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barrier[0].subresourceRange.levelCount = 1; + image_barrier[0].subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, NULL, 0, NULL, 1, image_barrier); + } + io.Fonts->TexID = (void *)(intptr_t)g_FontImage; + + io.Fonts->ClearInputData(); + io.Fonts->ClearTexData(); + + return true; +} + +bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() +{ + VkResult err; + + VkShaderModule vert_module; + VkShaderModule frag_module; + + // Create The Shader Modules: + { + VkShaderModuleCreateInfo vert_info = {}; + vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + vert_info.codeSize = __glsl_shader_vert_spv_len; + vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; + err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module); + ImGui_ImplGlfwVulkan_VkResult(err); + VkShaderModuleCreateInfo frag_info = {}; + frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + frag_info.codeSize = __glsl_shader_frag_spv_len; + frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; + err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); + ImGui_ImplGlfwVulkan_VkResult(err); + } + + if(!g_FontSampler){ + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.minLod = -1000; + info.maxLod = 1000; + err = vkCreateSampler(g_Device, + &info, + g_Allocator, + &g_FontSampler); + ImGui_ImplGlfwVulkan_VkResult(err); + } + + if(!g_DescriptorSetLayout){ + VkSampler sampler[1] = {g_FontSampler}; + VkDescriptorSetLayoutBinding binding[1] = {}; + binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding[0].descriptorCount = 1; + binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + binding[0].pImmutableSamplers = sampler; + VkDescriptorSetLayoutCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.bindingCount = 1; + info.pBindings = binding; + err = vkCreateDescriptorSetLayout(g_Device, + &info, + g_Allocator, + &g_DescriptorSetLayout); + ImGui_ImplGlfwVulkan_VkResult(err); + } + { + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = g_DescriptorPool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &g_DescriptorSetLayout; + err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet); + ImGui_ImplGlfwVulkan_VkResult(err); + } + if(!g_PipelineLayout){ + VkPushConstantRange push_constants[2] = {}; + push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constants[0].offset = sizeof(float) * 0; + push_constants[0].size = sizeof(float) * 2; + push_constants[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constants[1].offset = sizeof(float) * 2; + push_constants[1].size = sizeof(float) * 2; + VkDescriptorSetLayout set_layout[1] = {g_DescriptorSetLayout}; + VkPipelineLayoutCreateInfo layout_info = {}; + layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = set_layout; + layout_info.pushConstantRangeCount = 2; + layout_info.pPushConstantRanges = push_constants; + err = vkCreatePipelineLayout(g_Device, &layout_info, + g_Allocator, &g_PipelineLayout); + ImGui_ImplGlfwVulkan_VkResult(err); + } + + VkPipelineShaderStageCreateInfo stage[2] = {}; + stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stage[0].module = vert_module; + stage[0].pName = "main"; + stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stage[1].module = frag_module; + stage[1].pName = "main"; + + VkVertexInputBindingDescription binding_desc[1] = {}; + binding_desc[0].stride = sizeof(ImDrawVert); + binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + VkVertexInputAttributeDescription attribute_desc[3] = {}; + attribute_desc[0].location = 0; + attribute_desc[0].binding = binding_desc[0].binding; + attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; + attribute_desc[0].offset = (size_t)(&((ImDrawVert*)0)->pos); + attribute_desc[1].location = 1; + attribute_desc[1].binding = binding_desc[0].binding; + attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; + attribute_desc[1].offset = (size_t)(&((ImDrawVert*)0)->uv); + attribute_desc[2].location = 2; + attribute_desc[2].binding = binding_desc[0].binding; + attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; + attribute_desc[2].offset = (size_t)(&((ImDrawVert*)0)->col); + + VkPipelineVertexInputStateCreateInfo vertex_info = {}; + vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_info.vertexBindingDescriptionCount = 1; + vertex_info.pVertexBindingDescriptions = binding_desc; + vertex_info.vertexAttributeDescriptionCount = 3; + vertex_info.pVertexAttributeDescriptions = attribute_desc; + + VkPipelineInputAssemblyStateCreateInfo ia_info = {}; + ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineViewportStateCreateInfo viewport_info = {}; + viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_info.viewportCount = 1; + viewport_info.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo raster_info = {}; + raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + raster_info.polygonMode = VK_POLYGON_MODE_FILL; + raster_info.cullMode = VK_CULL_MODE_NONE; + raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + + VkPipelineMultisampleStateCreateInfo ms_info = {}; + ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState color_attachment[1] = {}; + color_attachment[0].blendEnable = VK_TRUE; + color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; + color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; + color_attachment[0].colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo blend_info = {}; + blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + blend_info.attachmentCount = 1; + blend_info.pAttachments = color_attachment; + + VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamic_state = {}; + dynamic_state.dynamicStateCount = 2; + dynamic_state.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + info.flags = g_PipelineCreateFlags; + info.stageCount = 2; + info.pStages = stage; + info.pVertexInputState = &vertex_info; + info.pInputAssemblyState = &ia_info; + info.pViewportState = &viewport_info; + info.pRasterizationState = &raster_info; + info.pMultisampleState = &ms_info; + info.pColorBlendState = &blend_info; + info.pDynamicState = &dynamic_state; + info.layout = g_PipelineLayout; + info.renderPass = g_RenderPass; + err = vkCreateGraphicsPipelines(g_Device, + g_PipelineCache, + 1, &info, + g_Allocator, + &g_Pipeline); + ImGui_ImplGlfwVulkan_VkResult(err); + + vkDestroyShaderModule(g_Device, vert_module, g_Allocator); + vkDestroyShaderModule(g_Device, frag_module, g_Allocator); + + return true; +} + +void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects() +{ + if(g_UploadBuffer){ + vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator); + g_UploadBuffer = VK_NULL_HANDLE; + } + if(g_UploadBufferMemory){ + vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator); + g_UploadBufferMemory = VK_NULL_HANDLE; + } +} +void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects() +{ + ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); + for(int i=0; iallocator; + g_Gpu = init_data->gpu; + g_Device = init_data->device; + g_RenderPass = init_data->render_pass; + g_PipelineCache = init_data->pipeline_cache; + g_DescriptorPool = init_data->descriptor_pool; + g_CheckVkResult = init_data->check_vk_result; + + g_Window = window; + + ImGuiIO& io = ImGui::GetIO(); + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; + io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; + io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; + io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; + io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; + io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; + io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; + io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; + io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; + io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; + io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; + io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + + io.RenderDrawListsFn = ImGui_ImplGlfwVulkan_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. + io.SetClipboardTextFn = ImGui_ImplGlfwVulkan_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfwVulkan_GetClipboardText; +#ifdef _WIN32 + io.ImeWindowHandle = glfwGetWin32Window(g_Window); +#endif + + if (install_callbacks) + { + glfwSetMouseButtonCallback(window, ImGui_ImplGlfwVulkan_MouseButtonCallback); + glfwSetScrollCallback(window, ImGui_ImplGlfwVulkan_ScrollCallback); + glfwSetKeyCallback(window, ImGui_ImplGlfwVulkan_KeyCallback); + glfwSetCharCallback(window, ImGui_ImplGlfwVulkan_CharCallback); + } + + ImGui_ImplGlfwVulkan_CreateDeviceObjects(); + + return true; +} + +void ImGui_ImplGlfwVulkan_Shutdown() +{ + ImGui_ImplGlfwVulkan_InvalidateDeviceObjects(); + ImGui::Shutdown(); +} + +void ImGui_ImplGlfwVulkan_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(g_Window, &w, &h); + glfwGetFramebufferSize(g_Window, &display_w, &display_h); + io.DisplaySize = ImVec2((float)w, (float)h); + io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); + g_Time = current_time; + + // Setup inputs + // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) + if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) + } + else + { + io.MousePos = ImVec2(-1,-1); + } + + for (int i = 0; i < 3; i++) + { + io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + g_MousePressed[i] = false; + } + + io.MouseWheel = g_MouseWheel; + g_MouseWheel = 0.0f; + + // Hide OS mouse cursor if ImGui is drawing it + glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); + + // Start the frame + ImGui::NewFrame(); +} +void ImGui_ImplGlfwVulkan_Render(VkCommandBuffer command_buffer) +{ + g_CommandBuffer = command_buffer; + ImGui::Render(); + g_CommandBuffer = VK_NULL_HANDLE; + g_FrameIndex = (g_FrameIndex+1)%IMGUI_VK_QUEUED_FRAMES; +} diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.h b/examples/vulkan_example/imgui_impl_glfw_vulkan.h new file mode 100644 index 00000000..3c04ed63 --- /dev/null +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.h @@ -0,0 +1,41 @@ +// ImGui GLFW binding with Vulkan + shaders +// 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 5 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXX_CreateFontsTexture(), ImGui_ImplXXXX_NewFrame(), ImGui_ImplXXXX_Render() and ImGui_ImplXXXX_Shutdown(). +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +#define IMGUI_VK_QUEUED_FRAMES 2 + +struct GLFWwindow; + +struct ImGui_ImplGlfwVulkan_Init_Data{ + VkAllocationCallbacks* allocator; + VkPhysicalDevice gpu; + VkDevice device; + VkRenderPass render_pass; + VkPipelineCache pipeline_cache; + VkDescriptorPool descriptor_pool; + void (*check_vk_result)(VkResult err); +}; + +IMGUI_API bool ImGui_ImplGlfwVulkan_Init(GLFWwindow* window, bool install_callbacks, ImGui_ImplGlfwVulkan_Init_Data *init_data); +IMGUI_API void ImGui_ImplGlfwVulkan_Shutdown(); +IMGUI_API void ImGui_ImplGlfwVulkan_NewFrame(); +IMGUI_API void ImGui_ImplGlfwVulkan_Render(VkCommandBuffer command_buffer); + +// Use if you want to reset your rendering device without losing ImGui state. +IMGUI_API void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); +IMGUI_API void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects(); +IMGUI_API bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); +IMGUI_API bool ImGui_ImplGlfwVulkan_CreateDeviceObjects(); + + +// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) +// Provided here if you want to chain callbacks. +// You can also handle inputs yourself and use those as a reference. +IMGUI_API void ImGui_ImplGlfwVulkan_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +IMGUI_API void ImGui_ImplGlfwVulkan_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); +IMGUI_API void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +IMGUI_API void ImGui_ImplGlfwVulkan_CharCallback(GLFWwindow* window, unsigned int c); + + diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp new file mode 100644 index 00000000..c42bcdf6 --- /dev/null +++ b/examples/vulkan_example/main.cpp @@ -0,0 +1,533 @@ +// ImGui - standalone example application for Glfw + Vulkan, using programmable pipeline +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. + +#include + +#include +#include +#define GLFW_INCLUDE_NONE +#define GLFW_INCLUDE_VULKAN +#include + +#include "imgui_impl_glfw_vulkan.h" + +#define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16 + +static VkAllocationCallbacks* g_Allocator = NULL; +static VkInstance g_Instance = VK_NULL_HANDLE; +static VkSurfaceKHR g_Surface = VK_NULL_HANDLE; +static VkPhysicalDevice g_Gpu = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static VkSwapchainKHR g_Swapchain = VK_NULL_HANDLE; +static VkRenderPass g_RenderPass = VK_NULL_HANDLE; +static uint32_t g_QueueFamily = 0; +static VkQueue g_Queue = VK_NULL_HANDLE; + +static VkFormat g_Format = VK_FORMAT_B8G8R8A8_UNORM; +static VkColorSpaceKHR g_ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; +static VkImageSubresourceRange g_ImageRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; + +static int fb_width, fb_height; +static uint32_t g_BackBufferIndex = 0; +static uint32_t g_BackBufferCount = 0; +static VkImage g_BackBuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; +static VkImageView g_BackBufferView[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; +static VkFramebuffer g_Framebuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; + +static uint32_t g_FrameIndex = 0; +static VkCommandPool g_CommandPool[IMGUI_VK_QUEUED_FRAMES]; +static VkCommandBuffer g_CommandBuffer[IMGUI_VK_QUEUED_FRAMES]; +static VkFence g_Fence[IMGUI_VK_QUEUED_FRAMES]; +static VkSemaphore g_Semaphore[IMGUI_VK_QUEUED_FRAMES]; + +static VkClearValue g_ClearValue = {}; + +static void check_vk_result(VkResult err) +{ + if(err == 0) return; + printf("VkResult %d\n", err); + if(err < 0) abort(); +} + +static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) +{ + VkResult err; + VkSwapchainKHR old_swapchain = g_Swapchain; + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + // Destroy old Framebuffer: + for(uint32_t i=0; iAddFontDefault(); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/Cousine-Regular.ttf", 15.0f); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/ProggyClean.ttf", 13.0f); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/ProggyTiny.ttf", 10.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); + + // Upload Fonts + { + VkResult err; + err = vkResetCommandPool(g_Device, g_CommandPool[g_FrameIndex], 0); + check_vk_result(err); + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(g_CommandBuffer[g_FrameIndex], &begin_info); + check_vk_result(err); + + ImGui_ImplGlfwVulkan_CreateFontsTexture(g_CommandBuffer[g_FrameIndex]); + + VkSubmitInfo end_info = {}; + end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + end_info.commandBufferCount = 1; + end_info.pCommandBuffers = &g_CommandBuffer[g_FrameIndex]; + err = vkEndCommandBuffer(g_CommandBuffer[g_FrameIndex]); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); + check_vk_result(err); + + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); + } + + bool show_test_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImColor(114, 144, 154); + + // Main loop + while (!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + ImGui_ImplGlfwVulkan_NewFrame(); + + // 1. Show a simple window + // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" + { + static float f = 0.0f; + ImGui::Text("Hello, world!"); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + ImGui::ColorEdit3("clear color", (float*)&clear_color); + if (ImGui::Button("Test Window")) show_test_window ^= 1; + if (ImGui::Button("Another Window")) show_another_window ^= 1; + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + } + + // 2. Show another simple window, this time using an explicit Begin/End pair + if (show_another_window) + { + ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Another Window", &show_another_window); + ImGui::Text("Hello"); + ImGui::End(); + } + + // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow() + if (show_test_window) + { + ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver); + ImGui::ShowTestWindow(&show_test_window); + } + + g_ClearValue.color.float32[0] = clear_color.x; + g_ClearValue.color.float32[1] = clear_color.y; + g_ClearValue.color.float32[2] = clear_color.z; + g_ClearValue.color.float32[3] = clear_color.w; + + frame_begin(); + + ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]); + + frame_end(); + } + + // Cleanup + VkResult err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplGlfwVulkan_Shutdown(); + cleanup_vulkan(); + glfwTerminate(); + + return 0; +} From 0ceddc29ff5b80dd270b7810f6bfa931c8353e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Wed, 9 Mar 2016 17:01:38 +0100 Subject: [PATCH 016/400] Vulkan Example: Fix windows build. --- examples/vulkan_example/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/vulkan_example/CMakeLists.txt b/examples/vulkan_example/CMakeLists.txt index daa7a171..3657c829 100644 --- a/examples/vulkan_example/CMakeLists.txt +++ b/examples/vulkan_example/CMakeLists.txt @@ -9,7 +9,7 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES") # GLFW -set(GLFW_DIR ../../../glfw) +set(GLFW_DIR ../../../glfw) # Set this to point to a up-to-date GLFW repo option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) @@ -23,12 +23,12 @@ set(IMGUI_DIR ../../) include_directories(${IMGUI_DIR}) # Libraries -if(WIN32) - set(LIBRARIES "glfw;vulkan-${MAJOR}") -elseif(UNIX) - set(LIBRARIES "glfw;vulkan") -else() -endif() +find_library(VULKAN_LIBRARY + NAMES vulkan vulkan-1) +set(LIBRARIES "glfw;${VULKAN_LIBRARY}") + +# Use vulkan headers from glfw: +include_directories(${GLFW_DIR}/deps) file(GLOB sources *.cpp) From 4ea4fa3e7318af552c5ea8fd36360babcb51c9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Thu, 10 Mar 2016 11:59:42 +0100 Subject: [PATCH 017/400] Vulkan Example: Fix synchronization. --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 10 +--------- examples/vulkan_example/main.cpp | 8 -------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 7ca1ab9f..ae479056 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -605,14 +605,6 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) } // Upload Barrier: { - VkBufferMemoryBarrier buffer_barrier[1] = {}; - buffer_barrier[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - buffer_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; - buffer_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - buffer_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - buffer_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - buffer_barrier[0].buffer = g_UploadBuffer; - buffer_barrier[0].size = upload_size; VkImageMemoryBarrier image_barrier[1] = {}; image_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -628,7 +620,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, NULL, 1, buffer_barrier, 1, image_barrier); + 0, NULL, 0, NULL, 1, image_barrier); } // Copy to Image: { diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index c42bcdf6..293f0557 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -311,14 +311,6 @@ static void frame_begin() if(err == VK_TIMEOUT) continue; check_vk_result(err); } - { - vkDestroySemaphore(g_Device, g_Semaphore[g_FrameIndex], g_Allocator); - VkSemaphoreCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(g_Device, &info, g_Allocator, - &g_Semaphore[g_FrameIndex]); - check_vk_result(err); - } { err = vkAcquireNextImageKHR( g_Device, g_Swapchain, From 1394616d9c87114d5c84b1deb6d75a58dc82d504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Thu, 10 Mar 2016 12:30:38 +0100 Subject: [PATCH 018/400] Vulkan Example: Some code layout changes. --- .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index ae479056..4774f173 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -228,7 +228,7 @@ static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties if((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<TexID = (void *)(intptr_t)g_FontImage; @@ -685,7 +679,6 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_FontSampler){ VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -703,7 +696,6 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() &g_FontSampler); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_DescriptorSetLayout){ VkSampler sampler[1] = {g_FontSampler}; VkDescriptorSetLayoutBinding binding[1] = {}; @@ -721,6 +713,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() &g_DescriptorSetLayout); ImGui_ImplGlfwVulkan_VkResult(err); } + // Create Descriptor Set: { VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; From 5abb39cb1f2fde6a4988a46548cafdd8727892af Mon Sep 17 00:00:00 2001 From: Daniel Martinek Date: Fri, 18 Mar 2016 14:02:14 +0100 Subject: [PATCH 019/400] Added support for CheckboxFlags that can set multiple flags at the same time. --- imgui.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c50a894e..62c5288c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6907,12 +6907,14 @@ bool ImGui::Checkbox(const char* label, bool* v) bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) { - bool v = (*flags & flags_value) ? true : false; + bool v = ((*flags & flags_value) == flags_value); bool pressed = ImGui::Checkbox(label, &v); - if (v) - *flags |= flags_value; - else - *flags &= ~flags_value; + if(pressed) { + if (v) + *flags |= flags_value; + else + *flags &= ~flags_value; + } return pressed; } From 37716184b34c84d589913b87e94bf774a905054f Mon Sep 17 00:00:00 2001 From: Daniel Martinek Date: Fri, 18 Mar 2016 16:49:19 +0100 Subject: [PATCH 020/400] Fixed coding style. --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 62c5288c..0baebacf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6909,12 +6909,14 @@ bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int f { bool v = ((*flags & flags_value) == flags_value); bool pressed = ImGui::Checkbox(label, &v); - if(pressed) { + if (pressed) + { if (v) *flags |= flags_value; else *flags &= ~flags_value; } + return pressed; } From 5bffc85ba64a5cb751f50345b01bab4ff9c0ab9d Mon Sep 17 00:00:00 2001 From: Kyle Rocha Date: Mon, 21 Mar 2016 12:07:13 -0700 Subject: [PATCH 021/400] Exposed FindTextDisplayEnd to imgui_internal.h --- imgui.cpp | 29 ++++++++++++++--------------- imgui_internal.h | 2 ++ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c50a894e..2bdb8590 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -591,7 +591,6 @@ //------------------------------------------------------------------------- static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); -static const char* FindTextDisplayEnd(const char* text, const char* text_end = NULL); static void PushMultiItemsWidths(int components, float w_full = 0.0f); static float GetDraggedColumnOffset(int column_index); @@ -2510,7 +2509,7 @@ void ImGui::Render() } // Find the optional ## from which we stop displaying text. -static const char* FindTextDisplayEnd(const char* text, const char* text_end) +const char* ImGui::FindTextDisplayEnd(const char* text, const char* text_end) { const char* text_display_end = text; if (!text_end) @@ -2549,7 +2548,7 @@ static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* ImGuiWindow* window = ImGui::GetCurrentWindowRead(); if (!text_end) - text_end = FindTextDisplayEnd(text, text_end); + text_end = ImGui::FindTextDisplayEnd(text, text_end); const bool log_new_line = ref_pos.y > window->DC.LogLinePosY+1; window->DC.LogLinePosY = ref_pos.y; @@ -2603,7 +2602,7 @@ void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool const char* text_display_end; if (hide_text_after_hash) { - text_display_end = FindTextDisplayEnd(text, text_end); + text_display_end = ImGui::FindTextDisplayEnd(text, text_end); } else { @@ -2642,7 +2641,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImVec2* clip_min, const ImVec2* clip_max) { // Hide anything after a '##' string - const char* text_display_end = FindTextDisplayEnd(text, text_end); + const char* text_display_end = ImGui::FindTextDisplayEnd(text, text_end); const int text_len = (int)(text_display_end - text); if (text_len == 0) return; @@ -2749,7 +2748,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex const char* text_display_end; if (hide_text_after_double_hash) - text_display_end = FindTextDisplayEnd(text, text_end); // Hide anything after a '##' string + text_display_end = ImGui::FindTextDisplayEnd(text, text_end); // Hide anything after a '##' string else text_display_end = text_end; @@ -6334,7 +6333,7 @@ bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_mi } ImGui::PopID(); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6376,7 +6375,7 @@ bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int } ImGui::PopID(); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6556,7 +6555,7 @@ bool ImGui::DragFloatN(const char* label, float* v, int components, float v_spee } ImGui::PopID(); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6595,7 +6594,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu ImGui::PopItemWidth(); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); ImGui::PopID(); @@ -6634,7 +6633,7 @@ bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, i } ImGui::PopID(); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6673,7 +6672,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ ImGui::PopItemWidth(); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); ImGui::PopID(); @@ -7893,7 +7892,7 @@ bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal ImGui::PopID(); window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); return value_changed; @@ -7936,7 +7935,7 @@ bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextF ImGui::PopID(); window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); - ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); ImGui::EndGroup(); return value_changed; @@ -8647,7 +8646,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! } - const char* label_display_end = FindTextDisplayEnd(label); + const char* label_display_end = ImGui::FindTextDisplayEnd(label); if (label != label_display_end) { ImGui::SameLine(0, (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) ? -1.0f : style.ItemInnerSpacing.x); diff --git a/imgui_internal.h b/imgui_internal.h index f6300e74..d6fc78ae 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -683,6 +683,8 @@ namespace ImGui IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); + const char* FindTextDisplayEnd(const char* text, const char* text_end = NULL); + IMGUI_API void EndFrame(); // Automatically called by Render() IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); From 3f46d9b9337e7ed0f5526f7f4c4dfda2e5c2820f Mon Sep 17 00:00:00 2001 From: Kyle Rocha Date: Mon, 21 Mar 2016 12:33:48 -0700 Subject: [PATCH 022/400] Renamed FindTextDisplayEnd to FindRenderedTextEnd --- imgui.cpp | 29 ++++++++++++++--------------- imgui_internal.h | 5 ++--- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2bdb8590..83fdc6e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2508,8 +2508,7 @@ void ImGui::Render() } } -// Find the optional ## from which we stop displaying text. -const char* ImGui::FindTextDisplayEnd(const char* text, const char* text_end) +const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) { const char* text_display_end = text; if (!text_end) @@ -2548,7 +2547,7 @@ static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* ImGuiWindow* window = ImGui::GetCurrentWindowRead(); if (!text_end) - text_end = ImGui::FindTextDisplayEnd(text, text_end); + text_end = ImGui::FindRenderedTextEnd(text, text_end); const bool log_new_line = ref_pos.y > window->DC.LogLinePosY+1; window->DC.LogLinePosY = ref_pos.y; @@ -2602,7 +2601,7 @@ void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool const char* text_display_end; if (hide_text_after_hash) { - text_display_end = ImGui::FindTextDisplayEnd(text, text_end); + text_display_end = FindRenderedTextEnd(text, text_end); } else { @@ -2641,7 +2640,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImVec2* clip_min, const ImVec2* clip_max) { // Hide anything after a '##' string - const char* text_display_end = ImGui::FindTextDisplayEnd(text, text_end); + const char* text_display_end = FindRenderedTextEnd(text, text_end); const int text_len = (int)(text_display_end - text); if (text_len == 0) return; @@ -2748,7 +2747,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex const char* text_display_end; if (hide_text_after_double_hash) - text_display_end = ImGui::FindTextDisplayEnd(text, text_end); // Hide anything after a '##' string + text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string else text_display_end = text_end; @@ -6333,7 +6332,7 @@ bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_mi } ImGui::PopID(); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6375,7 +6374,7 @@ bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int } ImGui::PopID(); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6555,7 +6554,7 @@ bool ImGui::DragFloatN(const char* label, float* v, int components, float v_spee } ImGui::PopID(); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6594,7 +6593,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu ImGui::PopItemWidth(); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); ImGui::PopID(); @@ -6633,7 +6632,7 @@ bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, i } ImGui::PopID(); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); return value_changed; @@ -6672,7 +6671,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ ImGui::PopItemWidth(); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); ImGui::PopID(); @@ -7892,7 +7891,7 @@ bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal ImGui::PopID(); window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); return value_changed; @@ -7935,7 +7934,7 @@ bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextF ImGui::PopID(); window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); - ImGui::TextUnformatted(label, ImGui::FindTextDisplayEnd(label)); + ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); ImGui::EndGroup(); return value_changed; @@ -8646,7 +8645,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! } - const char* label_display_end = ImGui::FindTextDisplayEnd(label); + const char* label_display_end = FindRenderedTextEnd(label); if (label != label_display_end) { ImGui::SameLine(0, (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) ? -1.0f : style.ItemInnerSpacing.x); diff --git a/imgui_internal.h b/imgui_internal.h index d6fc78ae..d5f97c60 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -683,8 +683,6 @@ namespace ImGui IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); - const char* FindTextDisplayEnd(const char* text, const char* text_end = NULL); - IMGUI_API void EndFrame(); // Automatically called by Render() IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); @@ -709,7 +707,8 @@ namespace ImGui IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); - IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); + IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_existing_clip_rect = true); IMGUI_API void PopClipRect(); From b8fcb4e7e450d536c2e881ae026a8f3227219865 Mon Sep 17 00:00:00 2001 From: Kyle Rocha Date: Mon, 21 Mar 2016 12:40:02 -0700 Subject: [PATCH 023/400] Converted tabs to spaces --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index d5f97c60..4df5ca94 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -708,7 +708,7 @@ namespace ImGui IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); - IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_existing_clip_rect = true); IMGUI_API void PopClipRect(); From a9e303e0064d7a698e46383bdc8f8f5a069abf02 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 12:56:56 -0700 Subject: [PATCH 024/400] Minor comments --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 5259a789..9731e31e 100644 --- a/imgui.h +++ b/imgui.h @@ -103,9 +103,9 @@ namespace ImGui // Main IMGUI_API ImGuiIO& GetIO(); IMGUI_API ImGuiStyle& GetStyle(); - IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame() + IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your io.RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame(). IMGUI_API void NewFrame(); - IMGUI_API void Render(); + IMGUI_API void Render(); // finalize rendering data, then call your io.RenderDrawListsFn() function if set. IMGUI_API void Shutdown(); IMGUI_API void ShowUserGuide(); // help block IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block From 86fb3a6a3c3c4a8ce2786bd1a937583a6b8acaef Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 21:48:05 +0100 Subject: [PATCH 025/400] ImDrawList: AddCircle() takes optional thickness parameter --- imgui.h | 2 +- imgui_draw.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 9731e31e..2764ff4b 100644 --- a/imgui.h +++ b/imgui.h @@ -1125,7 +1125,7 @@ struct ImDrawList IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); - IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); + IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9fbda0c6..77d596cd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -834,14 +834,14 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec PathFill(col); } -void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments) +void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness) { if ((col >> 24) == 0) return; const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments); - PathStroke(col, true); + PathStroke(col, true, thickness); } void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments) From 9cbc6e196b5b88e11263917920b441ede48084eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 21:56:23 +0100 Subject: [PATCH 026/400] ImDrawList: AddRect() added optional thickness parameter + updated demo --- imgui.h | 4 ++-- imgui_demo.cpp | 28 ++++++++++++++-------------- imgui_draw.cpp | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/imgui.h b/imgui.h index 2764ff4b..f484d6e3 100644 --- a/imgui.h +++ b/imgui.h @@ -1121,8 +1121,8 @@ struct ImDrawList // Primitives IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right - IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right + IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F, float thickness = 1.0f); // a: upper-left, b: lower-right + IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b2e4e09e..4b51e2bb 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1804,24 +1804,24 @@ static void ShowExampleAppCustomRendering(bool* opened) const ImVec2 p = ImGui::GetCursorScreenPos(); const ImU32 col32 = ImColor(col); float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f; - draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; - draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing; - draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32); x += spacing; - draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, 1.0f); - x = p.x + 4; - y += sz+spacing; + for (int n = 0; n < 2; n++) + { + float thickness = (n == 0) ? 1.0f : 4.0f; + draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, thickness); x += sz+spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ~0, thickness); x += sz+spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ~0, thickness); x += sz+spacing; + draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, thickness); x += sz+spacing; + draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, thickness); x += sz+spacing; + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, thickness); x += spacing; + draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, thickness); + x = p.x + 4; + y += sz+spacing; + } draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, 4.0f); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 4.0f); x += sz+spacing; - draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, 4.0f); x += spacing; - draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, 4.0f); x += sz+spacing; draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x+sz, y+sz), ImColor(0,0,0), ImColor(255,0,0), ImColor(255,255,0), ImColor(0,255,0)); - ImGui::Dummy(ImVec2((sz+spacing)*8, (sz+spacing)*2)); + ImGui::Dummy(ImVec2((sz+spacing)*8, (sz+spacing)*3)); } ImGui::Separator(); { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 77d596cd..5a8fe770 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -784,12 +784,12 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thic } // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly. -void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners) +void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners, float thickness) { if ((col >> 24) == 0) return; PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners); - PathStroke(col, true); + PathStroke(col, true, thickness); } void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners) From 928832a5bc93eb4285f73ef3e181a233a3abbe71 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 22:11:43 +0100 Subject: [PATCH 027/400] Various tidying up / comments, moved columns functions declarations, no functional changes --- imgui.cpp | 22 ++++++++++------------ imgui.h | 27 +++++++++++++++------------ imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8fca8fae..9d2d1413 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2826,13 +2826,13 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) // Test if mouse cursor is hovering given rectangle // NB- Rectangle is clipped by our current clip setting // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) -bool ImGui::IsMouseHoveringRect(const ImVec2& pos_min, const ImVec2& pos_max, bool clip) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindowRead(); // Clip - ImRect rect_clipped(pos_min, pos_max); + ImRect rect_clipped(r_min, r_max); if (clip) rect_clipped.Clip(window->ClipRect); @@ -8798,33 +8798,31 @@ void ImGui::EndGroup() } // Gets back to previous line and continue with horizontal layout -// local_pos_x == 0 : follow on previous item -// local_pos_x != 0 : align to specified column +// pos_x == 0 : follow on previous item +// pos_x != 0 : align to specified column // spacing_w < 0 : use default spacing if column_x==0, no spacing if column_x!=0 // spacing_w >= 0 : enforce spacing -void ImGui::SameLine(float local_pos_x, float spacing_w) +void ImGui::SameLine(float pos_x, float spacing_w) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; ImGuiState& g = *GImGui; - float x, y; - if (local_pos_x != 0.0f) + if (pos_x != 0.0f) { if (spacing_w < 0.0f) spacing_w = 0.0f; - x = window->Pos.x - window->Scroll.x + local_pos_x + spacing_w; - y = window->DC.CursorPosPrevLine.y; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } else { if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; - x = window->DC.CursorPosPrevLine.x + spacing_w; - y = window->DC.CursorPosPrevLine.y; + window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } window->DC.CurrentLineHeight = window->DC.PrevLineHeight; window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; - window->DC.CursorPos = ImVec2(x, y); } void ImGui::NextColumn() diff --git a/imgui.h b/imgui.h index f484d6e3..7e4b5917 100644 --- a/imgui.h +++ b/imgui.h @@ -189,18 +189,11 @@ namespace ImGui IMGUI_API void BeginGroup(); // lock horizontal starting position. once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line - IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally + IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally IMGUI_API void Spacing(); // add spacing IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) - IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); // setup number of columns. use an identifier to distinguish multiple column sets. close with Columns(1). - IMGUI_API void NextColumn(); // next column - IMGUI_API int GetColumnIndex(); // get current column index - IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this - IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column - IMGUI_API float GetColumnWidth(int column_index = -1); // column width (== GetColumnOffset(GetColumnIndex()+1) - GetColumnOffset(GetColumnOffset()) - IMGUI_API int GetColumnsCount(); // number of columns (what was passed to Columns()) IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position IMGUI_API float GetCursorPosX(); // " IMGUI_API float GetCursorPosY(); // " @@ -215,6 +208,16 @@ namespace ImGui IMGUI_API float GetTextLineHeightWithSpacing(); // distance (in pixels) between 2 consecutive lines of text == GetWindowFontSize() + GetStyle().ItemSpacing.y IMGUI_API float GetItemsLineHeightWithSpacing(); // distance (in pixels) between 2 consecutive lines of standard height widgets == GetWindowFontSize() + GetStyle().FramePadding.y*2 + GetStyle().ItemSpacing.y + // Columns + // You can also use SameLine(pos_x) for simplified columning. The columns API is still work-in-progress. + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); // setup number of columns. use an identifier to distinguish multiple column sets. close with Columns(1). + IMGUI_API void NextColumn(); // next column + IMGUI_API int GetColumnIndex(); // get current column index + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column + IMGUI_API float GetColumnWidth(int column_index = -1); // column width (== GetColumnOffset(GetColumnIndex()+1) - GetColumnOffset(GetColumnOffset()) + IMGUI_API int GetColumnsCount(); // number of columns (what was passed to Columns()) + // ID scopes // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them. // You can also use the "##foobar" syntax within widget label to distinguish them from each others. Read "A primer on the use of labels/IDs" in the FAQ for more details. @@ -330,7 +333,7 @@ namespace ImGui IMGUI_API void ValueColor(const char* prefix, const ImVec4& v); IMGUI_API void ValueColor(const char* prefix, unsigned int v); - // Tooltip + // Tooltips IMGUI_API void SetTooltip(const char* fmt, ...) IM_PRINTFARGS(1); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins IMGUI_API void SetTooltipV(const char* fmt, va_list args); IMGUI_API void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text @@ -346,7 +349,7 @@ namespace ImGui IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL - // Popup + // Popups IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API bool BeginPopup(const char* str_id); // return true if popup if opened and start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopupModal(const char* name, bool* p_opened = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (can't close them by clicking outside) @@ -407,7 +410,7 @@ namespace ImGui IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down) IMGUI_API bool IsMouseHoveringWindow(); // is mouse hovering current window ("window" in API names always refer to current window). disregarding of any consideration of being blocked by a popup. (unlike IsWindowHovered() this will return true even if the window is blocked because of a popup) IMGUI_API bool IsMouseHoveringAnyWindow(); // is mouse hovering any visible window - IMGUI_API bool IsMouseHoveringRect(const ImVec2& pos_min, const ImVec2& pos_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings. disregarding of consideration of focus/window ordering/blocked by a popup. + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings. disregarding of consideration of focus/window ordering/blocked by a popup. IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse positioning at the time of opening popup we have BeginPopup() into @@ -1255,7 +1258,7 @@ struct ImFontAtlas int TexWidth; // Texture width calculated during Build(). int TexHeight; // Texture height calculated during Build(). int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. - ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block) + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. // Private diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5a8fe770..a401b771 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -906,7 +906,7 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, _VtxCurrentIdx = (unsigned int)VtxBuffer.Size; } -// This is one of the few function breaking the encapsulation of ImDrawLst, but it is just so useful. +// [Uses global ImGui state] This is one of the few function breaking the encapsulation of ImDrawLst, but it is just so useful. void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) { if ((col >> 24) == 0) diff --git a/imgui_internal.h b/imgui_internal.h index 4df5ca94..554ef885 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -356,7 +356,7 @@ struct ImGuiState ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize() float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Size of characters. - ImVec2 FontTexUvWhitePixel; // (Shortcut) == Font->TexUvForWhite + ImVec2 FontTexUvWhitePixel; // (Shortcut) == Font->TexUvWhitePixel float Time; int FrameCount; From a274a09955219c6cca2614b58605696942c4261a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 22:29:11 +0100 Subject: [PATCH 028/400] Renamed GetWindowFont()->GetFont(), GetWindowFontSize()->GetFontSize() (related to #340) --- imgui.cpp | 12 +++++------- imgui.h | 8 +++++--- imgui_demo.cpp | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9d2d1413..7593bd47 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -149,6 +149,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. @@ -424,7 +425,6 @@ - window: get size/pos helpers given names (see discussion in #249) - window: a collapsed window can be stuck behind the main menu bar? - window: detect extra End() call that pop the "Debug" window out and assert at call site instead of later. - - window: consider renaming "GetWindowFont" which conflict with old Windows #define (#340) - window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic. - window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd. - draw-list: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). @@ -4828,16 +4828,14 @@ ImDrawList* ImGui::GetWindowDrawList() return window->DrawList; } -ImFont* ImGui::GetWindowFont() +ImFont* ImGui::GetFont() { - ImGuiState& g = *GImGui; - return g.Font; + return GImGui->Font; } -float ImGui::GetWindowFontSize() +float ImGui::GetFontSize() { - ImGuiState& g = *GImGui; - return g.FontSize; + return GImGui->FontSize; } void ImGui::SetWindowFontScale(float scale) diff --git a/imgui.h b/imgui.h index 7e4b5917..df23e7bd 100644 --- a/imgui.h +++ b/imgui.h @@ -126,14 +126,12 @@ namespace ImGui IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates IMGUI_API float GetWindowContentRegionWidth(); // IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives - IMGUI_API ImFont* GetWindowFont(); - IMGUI_API float GetWindowFontSize(); // size (also height in pixels) of current font with current scale applied - IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList api) IMGUI_API ImVec2 GetWindowSize(); // get current window size IMGUI_API float GetWindowWidth(); IMGUI_API float GetWindowHeight(); IMGUI_API bool IsWindowCollapsed(); + IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position. call before Begin() IMGUI_API void SetNextWindowPosCenter(ImGuiSetCond cond = 0); // set next window position to be centered on screen. call before Begin() @@ -171,6 +169,8 @@ namespace ImGui IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied @@ -435,6 +435,8 @@ namespace ImGui // Obsolete (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ + static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+ diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4b51e2bb..532a10c2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1108,7 +1108,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::InvisibleButton("##dummy", size); if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x+size.x,pos.y+size.y), ImColor(90,90,120,255)); - ImGui::GetWindowDrawList()->AddText(ImGui::GetWindowFont(), ImGui::GetWindowFontSize()*2.0f, ImVec2(pos.x+offset.x,pos.y+offset.y), ImColor(255,255,255,255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); + ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x+offset.x,pos.y+offset.y), ImColor(255,255,255,255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); ImGui::TreePop(); } } From 37d50dccf92543fd6f042fa7127ef6f6ff05137f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 22:30:32 +0100 Subject: [PATCH 029/400] Added GetFontTexUvWhitePixel() helper. --- imgui.cpp | 5 +++++ imgui.h | 1 + 2 files changed, 6 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 7593bd47..5bfa19d5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4838,6 +4838,11 @@ float ImGui::GetFontSize() return GImGui->FontSize; } +ImVec2 ImGui::GetFontTexUvWhitePixel() +{ + return GImGui->FontTexUvWhitePixel; +} + void ImGui::SetWindowFontScale(float scale) { ImGuiState& g = *GImGui; diff --git a/imgui.h b/imgui.h index df23e7bd..55f18692 100644 --- a/imgui.h +++ b/imgui.h @@ -171,6 +171,7 @@ namespace ImGui IMGUI_API void PopStyleVar(int count = 1); IMGUI_API ImFont* GetFont(); // get current font IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied From b495a52fc0267a852e0eb1f74f48b5d603679704 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 22:43:53 +0100 Subject: [PATCH 030/400] ImDrawList: Allow AddText(ImFont* font, float font_size, ...) to take NULL/0.0f as default --- imgui_draw.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a401b771..5faf91a2 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -874,6 +874,13 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, if (text_begin == text_end) return; + // Note: This is one of the few instance of breaking the encapsulation of ImDrawList, as we pull this from ImGui state, but it is just SO useful. + // Might just move Font/FontSize to ImDrawList? + if (font == NULL) + font = GImGui->Font; + if (font_size == 0.0f) + font_size = GImGui->FontSize; + IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. // reserve vertices for worse case (over-reserving is useful and easily amortized) @@ -906,12 +913,8 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, _VtxCurrentIdx = (unsigned int)VtxBuffer.Size; } -// [Uses global ImGui state] This is one of the few function breaking the encapsulation of ImDrawLst, but it is just so useful. void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) { - if ((col >> 24) == 0) - return; - AddText(GImGui->Font, GImGui->FontSize, pos, col, text_begin, text_end); } From 9260d46c2cc742d098726d3fea9d839d03460a4d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Mar 2016 22:51:51 +0100 Subject: [PATCH 031/400] Comments --- imgui_draw.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5faf91a2..08057b57 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1995,10 +1995,10 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re { char_width = glyph->XAdvance * scale; - // Clipping on Y is more likely + // Arbitrarily assume that both space and tabs are empty glyphs as an optimization if (c != ' ' && c != '\t') { - // We don't do a second finer clipping test on the Y axis (TODO: do some measurement see if it is worth it, probably not) + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w float y1 = (float)(y + glyph->Y0 * scale); float y2 = (float)(y + glyph->Y1 * scale); @@ -2042,8 +2042,8 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re } } - // NB: we are not calling PrimRectUV() here because non-inlined causes too much overhead in a debug build. - // inlined: + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug build. + // Inlined here: { idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); From 5bed7144fe5517c570162049b6b0ec935436931a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Mar 2016 20:10:06 +0100 Subject: [PATCH 032/400] ImDrawList: Added AddTriangle() function --- imgui.h | 1 + imgui_demo.cpp | 2 ++ imgui_draw.cpp | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/imgui.h b/imgui.h index 55f18692..77ad8e07 100644 --- a/imgui.h +++ b/imgui.h @@ -1130,6 +1130,7 @@ struct ImDrawList IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F, float thickness = 1.0f); // a: upper-left, b: lower-right IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); + IMGUI_API void AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness = 1.0f); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 532a10c2..a69374de 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1810,6 +1810,7 @@ static void ShowExampleAppCustomRendering(bool* opened) draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, thickness); x += sz+spacing; draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ~0, thickness); x += sz+spacing; draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ~0, thickness); x += sz+spacing; + draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, thickness); x += sz+spacing; draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, thickness); x += sz+spacing; draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, thickness); x += sz+spacing; draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, thickness); x += spacing; @@ -1820,6 +1821,7 @@ static void ShowExampleAppCustomRendering(bool* opened) draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing; draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing; + draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32); x += sz+spacing; draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x+sz, y+sz), ImColor(0,0,0), ImColor(255,0,0), ImColor(255,255,0), ImColor(0,255,0)); ImGui::Dummy(ImVec2((sz+spacing)*8, (sz+spacing)*3)); } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 08057b57..b82327c0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -823,6 +823,17 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left); } +void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness) +{ + if ((col >> 24) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathStroke(col, true, thickness); +} + void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col) { if ((col >> 24) == 0) From 367c53967f859bc0473ab76a3e156f3532b9300f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Mar 2016 21:17:24 +0100 Subject: [PATCH 033/400] Metrics: inspect individual triangles in drawcall --- imgui.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5bfa19d5..5e047819 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9265,10 +9265,14 @@ void ImGui::ShowMetricsWindow(bool* opened) { ImGui::SameLine(); ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + if (node_opened) ImGui::TreePop(); + return; } if (!node_opened) return; + ImDrawList* overlay_draw_list = &GImGui->OverlayDrawList; // Render additional visuals into the top-most draw list + overlay_draw_list->PushClipRectFullScreen(); int elem_offset = 0; for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) { @@ -9277,7 +9281,7 @@ void ImGui::ShowMetricsWindow(bool* opened) ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); continue; } - ImGui::BulletText("Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool draw_opened = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); if (show_clip_rects && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; @@ -9285,12 +9289,28 @@ void ImGui::ShowMetricsWindow(bool* opened) ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); - GImGui->OverlayDrawList.PushClipRectFullScreen(); - clip_rect.Round(); GImGui->OverlayDrawList.AddRect(clip_rect.Min, clip_rect.Max, ImColor(255,255,0)); - vtxs_rect.Round(); GImGui->OverlayDrawList.AddRect(vtxs_rect.Min, vtxs_rect.Max, ImColor(255,0,255)); - GImGui->OverlayDrawList.PopClipRect(); + clip_rect.Round(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, ImColor(255,255,0)); + vtxs_rect.Round(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, ImColor(255,0,255)); } + if (!draw_opened) + continue; + for (int i = elem_offset; i+2 < elem_offset + (int)pcmd->ElemCount; i += 3) + { + ImVec2 triangles_pos[3]; + char buf[300], *buf_p = buf; + for (int n = 0; n < 3; n++) + { + ImDrawVert& v = draw_list->VtxBuffer[(draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data[i+n] : i+n]; + triangles_pos[n] = v.pos; + buf_p += sprintf(buf_p, "vtx %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", i+n, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + ImGui::Selectable(buf, false); + if (ImGui::IsItemHovered()) + overlay_draw_list->AddPolyline(triangles_pos, 3, ImColor(255,255,0), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle + } + ImGui::TreePop(); } + overlay_draw_list->PopClipRect(); ImGui::TreePop(); } From 04396ed7a972faba8099a2ee961137b0b4e04015 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Mar 2016 11:00:47 +0100 Subject: [PATCH 034/400] FAQ and comments about the use of ImTextureID (#562, #561, #521, #510, #497, #475 ...) --- examples/allegro5_example/imgui_impl_a5.cpp | 2 ++ examples/allegro5_example/imgui_impl_a5.h | 2 ++ examples/directx10_example/imgui_impl_dx10.cpp | 2 ++ examples/directx10_example/imgui_impl_dx10.h | 2 ++ examples/directx11_example/imgui_impl_dx11.cpp | 2 ++ examples/directx11_example/imgui_impl_dx11.h | 2 ++ examples/directx9_example/imgui_impl_dx9.cpp | 2 ++ examples/directx9_example/imgui_impl_dx9.h | 2 ++ examples/ios_example/imguiex/imgui_impl_ios.h | 12 ++++++------ examples/ios_example/imguiex/imgui_impl_ios.mm | 7 ++++--- .../marmalade_example/imgui_impl_marmalade.cpp | 2 ++ .../marmalade_example/imgui_impl_marmalade.h | 2 ++ examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 2 ++ examples/opengl3_example/imgui_impl_glfw_gl3.h | 2 ++ examples/opengl_example/imgui_impl_glfw.cpp | 2 ++ examples/opengl_example/imgui_impl_glfw.h | 2 ++ .../sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 2 ++ .../sdl_opengl3_example/imgui_impl_sdl_gl3.h | 2 ++ examples/sdl_opengl_example/imgui_impl_sdl.cpp | 2 ++ examples/sdl_opengl_example/imgui_impl_sdl.h | 2 ++ imgui.cpp | 16 +++++++++++++--- imgui.h | 2 +- 22 files changed, 60 insertions(+), 13 deletions(-) diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index 0b1b8ed2..a4cce9fd 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -1,4 +1,6 @@ // ImGui Allegro 5 bindings +// In this binding, ImTextureID is used to store a 'ALLEGRO_BITMAP*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/allegro5_example/imgui_impl_a5.h b/examples/allegro5_example/imgui_impl_a5.h index 721f510e..b7439fef 100644 --- a/examples/allegro5_example/imgui_impl_a5.h +++ b/examples/allegro5_example/imgui_impl_a5.h @@ -1,4 +1,6 @@ // ImGui Allegro 5 bindings +// In this binding, ImTextureID is used to store a 'ALLEGRO_BITMAP*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 628bd41c..73bd3abf 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -1,4 +1,6 @@ // ImGui Win32 + DirectX10 binding +// In this binding, ImTextureID is used to store a 'ID3D10ShaderResourceView*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/directx10_example/imgui_impl_dx10.h b/examples/directx10_example/imgui_impl_dx10.h index 922cdaf2..7877e775 100644 --- a/examples/directx10_example/imgui_impl_dx10.h +++ b/examples/directx10_example/imgui_impl_dx10.h @@ -1,4 +1,6 @@ // ImGui Win32 + DirectX10 binding +// In this binding, ImTextureID is used to store a 'ID3D10ShaderResourceView*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 184ec036..2ac50c3c 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -1,4 +1,6 @@ // ImGui Win32 + DirectX11 binding +// In this binding, ImTextureID is used to store a 'ID3D11ShaderResourceView*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/directx11_example/imgui_impl_dx11.h b/examples/directx11_example/imgui_impl_dx11.h index 1145b897..7d6f710f 100644 --- a/examples/directx11_example/imgui_impl_dx11.h +++ b/examples/directx11_example/imgui_impl_dx11.h @@ -1,4 +1,6 @@ // ImGui Win32 + DirectX11 binding +// In this binding, ImTextureID is used to store a 'ID3D11ShaderResourceView*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index cc4542be..eb6f68b4 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -1,4 +1,6 @@ // ImGui Win32 + DirectX9 binding +// In this binding, ImTextureID is used to store a 'LPDIRECT3DTEXTURE9' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/directx9_example/imgui_impl_dx9.h b/examples/directx9_example/imgui_impl_dx9.h index 0681b376..090ca998 100644 --- a/examples/directx9_example/imgui_impl_dx9.h +++ b/examples/directx9_example/imgui_impl_dx9.h @@ -1,4 +1,6 @@ // ImGui Win32 + DirectX9 binding +// In this binding, ImTextureID is used to store a 'LPDIRECT3DTEXTURE9' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/ios_example/imguiex/imgui_impl_ios.h b/examples/ios_example/imguiex/imgui_impl_ios.h index 132e589d..9b01dd3b 100644 --- a/examples/ios_example/imguiex/imgui_impl_ios.h +++ b/examples/ios_example/imguiex/imgui_impl_ios.h @@ -1,9 +1,9 @@ -// -// imgui_impl_ios.h -// imguiex -// -// Joel Davis (joeld42@gmail.com) -// +// ImGui iOS+OpenGL+Synergy binding +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. +// Providing a standalone iOS application with Synergy integration makes this sample more verbose than others. It also hasn't been tested as much. +// Refer to other examples to get an easier understanding of how to integrate ImGui into your existing application. + +// by Joel Davis (joeld42@gmail.com) #pragma once diff --git a/examples/ios_example/imguiex/imgui_impl_ios.mm b/examples/ios_example/imguiex/imgui_impl_ios.mm index 2b8c3531..ab3fcd87 100644 --- a/examples/ios_example/imguiex/imgui_impl_ios.mm +++ b/examples/ios_example/imguiex/imgui_impl_ios.mm @@ -1,6 +1,7 @@ -// -// imgui_impl_ios.cpp -// imguiex +// ImGui iOS+OpenGL+Synergy binding +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. +// Providing a standalone iOS application with Synergy integration makes this sample more verbose than others. It also hasn't been tested as much. +// Refer to other examples to get an easier understanding of how to integrate ImGui into your existing application. #import #import diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index a9f9bf2e..e1d68a78 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -1,4 +1,6 @@ // ImGui Marmalade binding with IwGx +// In this binding, ImTextureID is used to store a 'CIwTexture*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/marmalade_example/imgui_impl_marmalade.h b/examples/marmalade_example/imgui_impl_marmalade.h index cad73661..5342cb7e 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.h +++ b/examples/marmalade_example/imgui_impl_marmalade.h @@ -1,4 +1,6 @@ // ImGui Marmalade binding with IwGx +// In this binding, ImTextureID is used to store a 'CIwTexture*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index fe895fb0..7cad27b0 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -1,4 +1,6 @@ // ImGui GLFW binding with OpenGL3 + shaders +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h index 818b9ffc..83c69aa8 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.h +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h @@ -1,4 +1,6 @@ // ImGui GLFW binding with OpenGL3 + shaders +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 54943e1d..335e4213 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -1,4 +1,6 @@ // ImGui GLFW binding with OpenGL +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h index 7c1efeef..09778224 100644 --- a/examples/opengl_example/imgui_impl_glfw.h +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -1,4 +1,6 @@ // ImGui GLFW binding with OpenGL +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index accaa60a..bf47a7a1 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -1,4 +1,6 @@ // ImGui SDL2 binding with OpenGL3 +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h index 3bbd0a7d..6205284a 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h @@ -1,4 +1,6 @@ // ImGui SDL2 binding with OpenGL3 +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index a8429a25..8359fd8a 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -1,4 +1,6 @@ // ImGui SDL2 binding with OpenGL +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.h b/examples/sdl_opengl_example/imgui_impl_sdl.h index cb65c3b4..e298365d 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.h +++ b/examples/sdl_opengl_example/imgui_impl_sdl.h @@ -1,4 +1,6 @@ // ImGui SDL2 binding with OpenGL +// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/imgui.cpp b/imgui.cpp index 5e047819..2510de3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -19,9 +19,10 @@ - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS - How can I help? - How do I update to a newer version of ImGui? + - What is ImTextureID and how do I display an image? - Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) / A primer on the use of labels/IDs in ImGui. - I integrated ImGui in my engine and the text or lines are blurry.. - - I integrated ImGui in my engine and some elements are disappearing when I move windows around.. + - I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - How can I load a different font than the default? - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? @@ -258,6 +259,15 @@ Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name in the code, there will likely be a comment about it. Please report any issue to the GitHub page! + + Q: What is ImTextureID and how do I display an image? + A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function. + ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry! + It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc. + At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render. + Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing. + c++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address! + Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) A: Yes. A primer on the use of labels/IDs in ImGui.. @@ -355,8 +365,8 @@ A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. - Q. I integrated ImGui in my engine and some elements are disappearing when I move windows around.. - Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height). + Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. + A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height). Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) A: Use the font atlas to load the TTF file you want: diff --git a/imgui.h b/imgui.h index 77ad8e07..162a2aea 100644 --- a/imgui.h +++ b/imgui.h @@ -58,7 +58,7 @@ struct ImGuiListClipper; // Helper to manually clip large list of ite // Enumerations (declared as int for compatibility and to not pollute the top of this file) typedef unsigned int ImU32; typedef unsigned short ImWchar; // character for keyboard input/display -typedef void* ImTextureID; // user data to refer to a texture (e.g. store your texture handle/id) +typedef void* ImTextureID; // user data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) typedef ImU32 ImGuiID; // unique ID used by widgets (typically hashed from a stack of string) typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_ typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_ From 5b8aa0dc844af7bac20af204e462c7f199db2fd4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Mar 2016 11:06:57 +0100 Subject: [PATCH 035/400] FAQ and comments about the use of ImTextureID (#562, #561, #521, #510, #497, #475) --- imgui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 2510de3e..254d04db 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -266,7 +266,10 @@ It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc. At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render. Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing. - c++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address! + (c++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!) + To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions. + ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use. + It is your responsibility to get textures uploaded to your GPU. Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) A: Yes. A primer on the use of labels/IDs in ImGui.. From adb4d4d48b2f600af18cbd9ef9158427a179db8a Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Thu, 24 Mar 2016 19:37:11 +0100 Subject: [PATCH 036/400] Fix compilation on DragonFly BSD --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b82327c0..b2559c45 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -18,7 +18,7 @@ #include "imgui_internal.h" #include // vsnprintf, sscanf, printf -#if !defined(alloca) && !defined(__FreeBSD__) +#if !defined(alloca) && !defined(__FreeBSD__) && !defined(__DragonFly__) #ifdef _WIN32 #include // alloca #else From aecf5d12e6a3e4f58f5a3e1de918460061de62f8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Mar 2016 21:53:59 +0100 Subject: [PATCH 037/400] DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly after a text input modification (#564) --- imgui.cpp | 61 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 254d04db..eb5e4f62 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -652,7 +652,7 @@ static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size); static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size); static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2); -static void DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format); +static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format); //----------------------------------------------------------------------------- // Platform dependent default implementations @@ -5931,7 +5931,7 @@ static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const } // User can input math operators (e.g. +100) to edit a numerical values. -static void DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format) +static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format) { while (ImCharIsSpace(*buf)) buf++; @@ -5950,41 +5950,47 @@ static void DataTypeApplyOpFromText(const char* buf, const char* initial_value_b op = 0; } if (!buf[0]) - return; + return false; if (data_type == ImGuiDataType_Int) { if (!scalar_format) scalar_format = "%d"; int* v = (int*)data_ptr; - int ref_v = *v; - if (op && sscanf(initial_value_buf, scalar_format, &ref_v) < 1) - return; + const int old_v = *v; + int arg0 = *v; + if (op && sscanf(initial_value_buf, scalar_format, &arg0) < 1) + return false; // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision - float op_v = 0.0f; - if (op == '+') { if (sscanf(buf, "%f", &op_v) == 1) *v = (int)(ref_v + op_v); } // Add (use "+-" to subtract) - else if (op == '*') { if (sscanf(buf, "%f", &op_v) == 1) *v = (int)(ref_v * op_v); } // Multiply - else if (op == '/') { if (sscanf(buf, "%f", &op_v) == 1 && op_v != 0.0f) *v = (int)(ref_v / op_v); }// Divide - else { if (sscanf(buf, scalar_format, &ref_v) == 1) *v = ref_v; } // Assign constant + float arg1 = 0.0f; + if (op == '+') { if (sscanf(buf, "%f", &arg1) == 1) *v = (int)(arg0 + arg1); } // Add (use "+-" to subtract) + else if (op == '*') { if (sscanf(buf, "%f", &arg1) == 1) *v = (int)(arg0 * arg1); } // Multiply + else if (op == '/') { if (sscanf(buf, "%f", &arg1) == 1 && arg1 != 0.0f) *v = (int)(arg0 / arg1); }// Divide + else { if (sscanf(buf, scalar_format, &arg0) == 1) *v = arg0; } // Assign constant + return (old_v != *v); } else if (data_type == ImGuiDataType_Float) { // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in scalar_format = "%f"; float* v = (float*)data_ptr; - float ref_v = *v; - if (op && sscanf(initial_value_buf, scalar_format, &ref_v) < 1) - return; - float op_v = 0.0f; - if (sscanf(buf, scalar_format, &op_v) < 1) - return; + const float old_v = *v; + float arg0 = *v; + if (op && sscanf(initial_value_buf, scalar_format, &arg0) < 1) + return false; - if (op == '+') { *v = ref_v + op_v; } // Add (use "+-" to subtract) - else if (op == '*') { *v = ref_v * op_v; } // Multiply - else if (op == '/') { if (op_v != 0.0f) *v = ref_v / op_v; } // Divide - else { *v = op_v; } // Assign constant + float arg1 = 0.0f; + if (sscanf(buf, scalar_format, &arg1) < 1) + return false; + if (op == '+') { *v = arg0 + arg1; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0 * arg1; } // Multiply + else if (op == '/') { if (arg1 != 0.0f) *v = arg0 / arg1; } // Divide + else { *v = arg1; } // Assign constant + return (old_v != *v); } + + return false; } // Create text input in place of a slider (when CTRL+Clicking on slider) @@ -6000,7 +6006,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label char buf[32]; DataTypeFormatString(data_type, data_ptr, decimal_precision, buf, IM_ARRAYSIZE(buf)); - bool value_changed = InputTextEx(label, buf, IM_ARRAYSIZE(buf), aabb.GetSize(), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll); + bool text_value_changed = InputTextEx(label, buf, IM_ARRAYSIZE(buf), aabb.GetSize(), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll); if (g.ScalarAsInputTextId == 0) { // First frame @@ -6013,9 +6019,9 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label // Release g.ScalarAsInputTextId = 0; } - if (value_changed) - DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, NULL); - return value_changed; + if (text_value_changed) + return DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, NULL); + return false; } // Parse display precision back from the display format string @@ -7837,10 +7843,7 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data extra_flags |= ImGuiInputTextFlags_CharsDecimal; extra_flags |= ImGuiInputTextFlags_AutoSelectAll; if (ImGui::InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) - { - DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format); - value_changed = true; - } + value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format); // Step buttons if (step_ptr) From a9b0abe493d4209660e68d0a1850b413c18fd941 Mon Sep 17 00:00:00 2001 From: Nick Gravelyn Date: Wed, 20 Jan 2016 06:06:31 -0800 Subject: [PATCH 038/400] Automatically updating DisplayFrameBufferScale by reading the OpenGL drawable size and comparing with the window size. This fixed dear imgui which was rendering only to 1/4 of my window. --- examples/sdl_opengl_example/imgui_impl_sdl.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index 8359fd8a..e222c806 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -240,6 +240,10 @@ void ImGui_ImplSdl_NewFrame(SDL_Window *window) SDL_GetWindowSize(window, &w, &h); io.DisplaySize = ImVec2((float)w, (float)h); + int glW, glH; + SDL_GL_GetDrawableSize(window, &glW, &glH); + io.DisplayFramebufferScale = ImVec2(glW / io.DisplaySize.x, glH / io.DisplaySize.y); + // Setup time step Uint32 time = SDL_GetTicks(); double current_time = time / 1000.0; From 8a61c0afeae9209c5a11ecfb50bbe4737e8edcbc Mon Sep 17 00:00:00 2001 From: Nick Gravelyn Date: Wed, 20 Jan 2016 06:11:28 -0800 Subject: [PATCH 039/400] Applying same fix to OpenGL 3 example. Fixing spaces/tabs. --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 5 ++++- examples/sdl_opengl_example/imgui_impl_sdl.cpp | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index bf47a7a1..db76fb46 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -352,7 +352,10 @@ void ImGui_ImplSdlGL3_NewFrame() int w, h; SDL_GetWindowSize(g_Window, &w, &h); io.DisplaySize = ImVec2((float)w, (float)h); - io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + + int glW, glH; + SDL_GL_GetDrawableSize(window, &glW, &glH); + io.DisplayFramebufferScale = ImVec2(glW / io.DisplaySize.x, glH / io.DisplaySize.y); // Setup time step Uint32 time = SDL_GetTicks(); diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index e222c806..47dac65b 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -240,9 +240,9 @@ void ImGui_ImplSdl_NewFrame(SDL_Window *window) SDL_GetWindowSize(window, &w, &h); io.DisplaySize = ImVec2((float)w, (float)h); - int glW, glH; - SDL_GL_GetDrawableSize(window, &glW, &glH); - io.DisplayFramebufferScale = ImVec2(glW / io.DisplaySize.x, glH / io.DisplaySize.y); + int glW, glH; + SDL_GL_GetDrawableSize(window, &glW, &glH); + io.DisplayFramebufferScale = ImVec2(glW / io.DisplaySize.x, glH / io.DisplaySize.y); // Setup time step Uint32 time = SDL_GetTicks(); From e6c2c1fcfd31a53a0411b1a844a3016e701d1ab7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Mar 2016 22:25:20 +0100 Subject: [PATCH 040/400] Examples: SDL: Minor fixes to follow syntax of other examples (#495) --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 7 +++---- examples/sdl_opengl_example/imgui_impl_sdl.cpp | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index db76fb46..a5c4c9d0 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -350,12 +350,11 @@ void ImGui_ImplSdlGL3_NewFrame() // Setup display size (every frame to accommodate for window resizing) int w, h; + int display_w, display_h; SDL_GetWindowSize(g_Window, &w, &h); + SDL_GL_GetDrawableSize(g_Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); - - int glW, glH; - SDL_GL_GetDrawableSize(window, &glW, &glH); - io.DisplayFramebufferScale = ImVec2(glW / io.DisplaySize.x, glH / io.DisplaySize.y); + io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); // Setup time step Uint32 time = SDL_GetTicks(); diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index 47dac65b..b84f5014 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -237,12 +237,11 @@ void ImGui_ImplSdl_NewFrame(SDL_Window *window) // Setup display size (every frame to accommodate for window resizing) int w, h; + int display_w, display_h; SDL_GetWindowSize(window, &w, &h); + SDL_GL_GetDrawableSize(window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); - - int glW, glH; - SDL_GL_GetDrawableSize(window, &glW, &glH); - io.DisplayFramebufferScale = ImVec2(glW / io.DisplaySize.x, glH / io.DisplaySize.y); + io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); // Setup time step Uint32 time = SDL_GetTicks(); From fdc4299c6ccfcabeb1316f42e43cc8129adf7a4f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Mar 2016 22:27:43 +0100 Subject: [PATCH 041/400] Examples: SDL: Made ImGui_ImplSdlGL3_NewFrame() signature match GL2 one --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 13 +++++-------- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h | 4 ++-- examples/sdl_opengl3_example/main.cpp | 2 +- examples/sdl_opengl_example/imgui_impl_sdl.cpp | 2 +- examples/sdl_opengl_example/imgui_impl_sdl.h | 4 ++-- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index a5c4c9d0..7afbf343 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -15,7 +15,6 @@ #include // Data -static SDL_Window* g_Window = NULL; static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; static float g_MouseWheel = 0.0f; @@ -296,10 +295,8 @@ void ImGui_ImplSdlGL3_InvalidateDeviceObjects() } } -bool ImGui_ImplSdlGL3_Init(SDL_Window *window) +bool ImGui_ImplSdlGL3_Init(SDL_Window* window) { - g_Window = window; - ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = SDLK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; @@ -341,7 +338,7 @@ void ImGui_ImplSdlGL3_Shutdown() ImGui::Shutdown(); } -void ImGui_ImplSdlGL3_NewFrame() +void ImGui_ImplSdlGL3_NewFrame(SDL_Window* window) { if (!g_FontTexture) ImGui_ImplSdlGL3_CreateDeviceObjects(); @@ -351,8 +348,8 @@ void ImGui_ImplSdlGL3_NewFrame() // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - SDL_GetWindowSize(g_Window, &w, &h); - SDL_GL_GetDrawableSize(g_Window, &display_w, &display_h); + SDL_GetWindowSize(window, &w, &h); + SDL_GL_GetDrawableSize(window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); @@ -366,7 +363,7 @@ void ImGui_ImplSdlGL3_NewFrame() // (we already got mouse wheel, keyboard keys & characters from SDL_PollEvent()) int mx, my; Uint32 mouseMask = SDL_GetMouseState(&mx, &my); - if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_MOUSE_FOCUS) + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS) io.MousePos = ImVec2((float)mx, (float)my); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) else io.MousePos = ImVec2(-1, -1); diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h index 6205284a..99abd409 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.h @@ -9,9 +9,9 @@ struct SDL_Window; typedef union SDL_Event SDL_Event; -IMGUI_API bool ImGui_ImplSdlGL3_Init(SDL_Window *window); +IMGUI_API bool ImGui_ImplSdlGL3_Init(SDL_Window* window); IMGUI_API void ImGui_ImplSdlGL3_Shutdown(); -IMGUI_API void ImGui_ImplSdlGL3_NewFrame(); +IMGUI_API void ImGui_ImplSdlGL3_NewFrame(SDL_Window* window); IMGUI_API bool ImGui_ImplSdlGL3_ProcessEvent(SDL_Event* event); // Use if you want to reset your rendering device without losing ImGui state. diff --git a/examples/sdl_opengl3_example/main.cpp b/examples/sdl_opengl3_example/main.cpp index 54d2749a..33b4903f 100644 --- a/examples/sdl_opengl3_example/main.cpp +++ b/examples/sdl_opengl3_example/main.cpp @@ -58,7 +58,7 @@ int main(int, char**) if (event.type == SDL_QUIT) done = true; } - ImGui_ImplSdlGL3_NewFrame(); + ImGui_ImplSdlGL3_NewFrame(window); // 1. Show a simple window // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index b84f5014..927f8774 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -185,7 +185,7 @@ void ImGui_ImplSdl_InvalidateDeviceObjects() } } -bool ImGui_ImplSdl_Init(SDL_Window *window) +bool ImGui_ImplSdl_Init(SDL_Window* window) { ImGuiIO& io = ImGui::GetIO(); io.KeyMap[ImGuiKey_Tab] = SDLK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.h b/examples/sdl_opengl_example/imgui_impl_sdl.h index e298365d..a322bf2d 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.h +++ b/examples/sdl_opengl_example/imgui_impl_sdl.h @@ -9,9 +9,9 @@ struct SDL_Window; typedef union SDL_Event SDL_Event; -IMGUI_API bool ImGui_ImplSdl_Init(SDL_Window *window); +IMGUI_API bool ImGui_ImplSdl_Init(SDL_Window* window); IMGUI_API void ImGui_ImplSdl_Shutdown(); -IMGUI_API void ImGui_ImplSdl_NewFrame(SDL_Window *window); +IMGUI_API void ImGui_ImplSdl_NewFrame(SDL_Window* window); IMGUI_API bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event); // Use if you want to reset your rendering device without losing ImGui state. From 7c9fa593293d92490bac84e4a77dd7c018541a99 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Mar 2016 22:55:45 +0100 Subject: [PATCH 042/400] Combo: Right-most button stays highlight when popup is open. --- imgui.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index eb5e4f62..d69608d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8048,10 +8048,12 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const float arrow_size = (g.FontSize + style.FramePadding.x * 2.0f); const bool hovered = IsHovered(frame_bb, id); + bool popup_opened = IsPopupOpen(id); + bool popup_opened_now = false; const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING + RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(popup_opened || hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING RenderCollapseTriangle(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y) + style.FramePadding, true); if (*current_item >= 0 && *current_item < items_count) @@ -8064,7 +8066,6 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - bool menu_toggled = false; if (hovered) { SetHoveredID(id); @@ -8078,8 +8079,8 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi else { FocusWindow(window); - ImGui::OpenPopup(label); - menu_toggled = true; + OpenPopup(label); + popup_opened = popup_opened_now = true; } } } @@ -8116,7 +8117,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi value_changed = true; *current_item = i; } - if (item_selected && menu_toggled) + if (item_selected && popup_opened_now) ImGui::SetScrollHere(); ImGui::PopID(); } From d6750c87c2b00552692b45369f265d234996fe07 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Mar 2016 23:36:43 +0100 Subject: [PATCH 043/400] Combo: display popup above if there's isn't enough space below / or select largest side (#505) --- imgui.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d69608d0..b5a37c0d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8093,8 +8093,15 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi height_in_items = 7; float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3); - ImRect popup_rect(ImVec2(frame_bb.Min.x, frame_bb.Max.y), ImVec2(frame_bb.Max.x, frame_bb.Max.y + popup_height)); - popup_rect.Max.y = ImMin(popup_rect.Max.y, g.IO.DisplaySize.y - style.DisplaySafeAreaPadding.y); // Adhoc height limit for Combo. Ideally should be handled in Begin() along with other popups size, we want to have the possibility of moving the popup above as well. + float popup_y1 = frame_bb.Max.y; + float popup_y2 = ImClamp(popup_y1 + popup_height, popup_y1, g.IO.DisplaySize.y - style.DisplaySafeAreaPadding.y); + if ((popup_y2 - popup_y1) < ImMin(popup_height, frame_bb.Min.y - style.DisplaySafeAreaPadding.y)) + { + // Position our combo ABOVE because there's more space to fit! (FIXME: Handle in Begin() or use a shared helper. We have similar code in Begin() for popup placement) + popup_y1 = ImClamp(frame_bb.Min.y - popup_height, style.DisplaySafeAreaPadding.y, frame_bb.Min.y); + popup_y2 = frame_bb.Min.y; + } + ImRect popup_rect(ImVec2(frame_bb.Min.x, popup_y1), ImVec2(frame_bb.Max.x, popup_y2)); ImGui::SetNextWindowPos(popup_rect.Min); ImGui::SetNextWindowSize(popup_rect.GetSize()); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); From 2b7eeba143fc0303526ce8f79eb729a0b9fe29cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 26 Mar 2016 15:38:52 +0100 Subject: [PATCH 044/400] Trim trailing spaces --- imgui.cpp | 38 +++++++++++++++++++------------------- imgui.h | 10 +++++----- imgui_demo.cpp | 28 ++++++++++++++-------------- imgui_draw.cpp | 24 ++++++++++++------------ imgui_internal.h | 2 +- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b5a37c0d..52348a12 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -108,7 +108,7 @@ unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height); - // TODO: At this points you've got a texture pointed to by 'pixels' and you need to upload that your your graphic system + // TODO: At this points you've got a texture pointed to by 'pixels' and you need to upload that your your graphic system // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID' // Application main loop @@ -309,7 +309,7 @@ Button("Hello###ID"; // Label = "Hello", ID = hash of "ID" Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above) - + sprintf(buf, "My game (%f FPS)###MyGame"); Begin(buf); // Variable label, ID = hash of "MyGame" @@ -447,7 +447,7 @@ - widgets: clean up widgets internal toward exposing everything. - widgets: add disabled and read-only modes (#211) - main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them. - - main: make it so that a frame with no window registered won't refocus every window on subsequent frames (~bump LastFrameActive of all windows). + - main: make it so that a frame with no window registered won't refocus every window on subsequent frames (~bump LastFrameActive of all windows). - main: IsItemHovered() make it 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: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) @@ -984,7 +984,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* if ((*str & 0xf0) == 0xe0) { *out_char = 0xFFFD; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 3) return 1; + if (in_text_end && in_text_end - (const char*)str < 3) return 1; if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below c = (unsigned int)((*str++ & 0x0f) << 12); @@ -2388,7 +2388,7 @@ void ImGui::EndFrame() // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.OsImePosRequest - g.OsImePosSet) > 0.0001f) { - g.IO.ImeSetInputScreenPosFn((int)g.OsImePosRequest.x, (int)g.OsImePosRequest.y); + g.IO.ImeSetInputScreenPosFn((int)g.OsImePosRequest.x, (int)g.OsImePosRequest.y); g.OsImePosSet = g.OsImePosRequest; } @@ -3141,7 +3141,7 @@ static bool IsPopupOpen(ImGuiID id) return opened; } -// Mark popup as open (toggle toward open state). +// Mark popup as open (toggle toward open state). // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) @@ -3319,11 +3319,11 @@ void ImGui::EndPopup() } // This is a helper to handle the most simple case of associating one named popup to one given widget. -// 1. If you have many possible popups (for different "instances" of a same widget, or for wholly different widgets), you may be better off handling +// 1. If you have many possible popups (for different "instances" of a same widget, or for wholly different widgets), you may be better off handling // this yourself so you can store data relative to the widget that opened the popup instead of choosing different popup identifiers. // 2. If you want right-clicking on the same item to reopen the popup at new location, use the same code replacing IsItemHovered() with IsItemHoveredRect() // and passing true to the OpenPopupEx(). -// Because: hovering an item in a window below the popup won't normally trigger is hovering behavior/coloring. The pattern of ignoring the fact that +// Because: hovering an item in a window below the popup won't normally trigger is hovering behavior/coloring. The pattern of ignoring the fact that // the item isn't interactable (because it is blocked by the active popup) may useful in some situation when e.g. large canvas as one item, content of menu // driven by click position. bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) @@ -3482,7 +3482,7 @@ static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, ImGuiWindow* ImGui::FindWindowByName(const char* name) { - // FIXME-OPT: Store sorted hashes -> pointers so we can do a bissection in a contiguous block + // FIXME-OPT: Store sorted hashes -> pointers so we can do a bissection in a contiguous block ImGuiState& g = *GImGui; ImGuiID id = ImHash(name, 0); for (int i = 0; i < g.Windows.Size; i++) @@ -3615,7 +3615,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ g.CurrentPopupStack.push_back(popup_ref); window->PopupID = popup_ref.PopupID; } - + const bool window_appearing_after_being_hidden = (window->HiddenFrames == 1); // Process SetNextWindow***() calls @@ -3763,7 +3763,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else { size_auto_fit = ImClamp(window->SizeContents + window->WindowPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding)); - + // Handling case of auto fit window not fitting in screen on one axis, we are growing auto fit size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding. if (size_auto_fit.x < window->SizeContents.x && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)) size_auto_fit.y += style.ScrollbarSize; @@ -5637,7 +5637,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display label = str_id; const bool label_hide_text_after_double_hash = (label == str_id); // Only search and hide text after ## if we have passed label and ID separately, otherwise allow "##" within format string. const ImGuiID id = window->GetID(str_id); - const ImVec2 label_size = CalcTextSize(label, NULL, label_hide_text_after_double_hash); + const ImVec2 label_size = CalcTextSize(label, NULL, label_hide_text_after_double_hash); // We vertically grow up to current line height up the typical widget height. const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset - padding.y); // Latch before ItemSize changes it @@ -6871,7 +6871,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f); overlay = overlay_buf; } - + ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb.Min, &bb.Max); @@ -6936,7 +6936,7 @@ bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int f else *flags &= ~flags_value; } - + return pressed; } @@ -7771,7 +7771,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (is_editable) - g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); + g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); } else { @@ -8663,7 +8663,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) const ImVec4 col_display(col[0], col[1], col[2], 1.0f); if (ImGui::ColorButton(col_display)) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! - + // Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here if (ImGui::IsItemHovered()) ImGui::SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8(col[0]), IM_F32_TO_INT8(col[1]), IM_F32_TO_INT8(col[2]), IM_F32_TO_INT8(col[3])); @@ -8760,7 +8760,7 @@ void ImGui::Dummy(const ImVec2& size) ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); ItemAdd(bb, NULL); @@ -9022,9 +9022,9 @@ void ImGui::Columns(int columns_count, const char* id, bool border) } } - // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. + // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. - ImGui::PushID(0x11223347 + (id ? 0 : columns_count)); + ImGui::PushID(0x11223347 + (id ? 0 : columns_count)); window->DC.ColumnsSetID = window->GetID(id ? id : "columns"); ImGui::PopID(); diff --git a/imgui.h b/imgui.h index 162a2aea..3b1ab1ed 100644 --- a/imgui.h +++ b/imgui.h @@ -105,7 +105,7 @@ namespace ImGui IMGUI_API ImGuiStyle& GetStyle(); IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your io.RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame(). IMGUI_API void NewFrame(); - IMGUI_API void Render(); // finalize rendering data, then call your io.RenderDrawListsFn() function if set. + IMGUI_API void Render(); // finalize rendering data, then call your io.RenderDrawListsFn() function if set. IMGUI_API void Shutdown(); IMGUI_API void ShowUserGuide(); // help block IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block @@ -124,7 +124,7 @@ namespace ImGui IMGUI_API float GetContentRegionAvailWidth(); // IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates - IMGUI_API float GetWindowContentRegionWidth(); // + IMGUI_API float GetWindowContentRegionWidth(); // IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList api) IMGUI_API ImVec2 GetWindowSize(); // get current window size @@ -137,7 +137,7 @@ namespace ImGui IMGUI_API void SetNextWindowPosCenter(ImGuiSetCond cond = 0); // set next window position to be centered on screen. call before Begin() IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (enforce the range of scrollbars). set axis to 0.0f to leave it automatic. call before Begin() - IMGUI_API void SetNextWindowContentWidth(float width); // set next window content width (enforce the range of horizontal scrollbar). call before Begin() + IMGUI_API void SetNextWindowContentWidth(float width); // set next window content width (enforce the range of horizontal scrollbar). call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. call before Begin() IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing @@ -351,7 +351,7 @@ namespace ImGui IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL // Popups - IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). + IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API bool BeginPopup(const char* str_id); // return true if popup if opened and start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopupModal(const char* name, bool* p_opened = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (can't close them by clicking outside) IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item. read comments in .cpp! @@ -711,7 +711,7 @@ struct ImGuiIO // User Functions //------------------------------------------------------------------ - // Rendering function, will be called in Render(). + // Rendering function, will be called in Render(). // Alternatively you can keep this to NULL and call GetDrawData() after Render() to get the same pointer. // See example applications if you are unsure of how to implement this. void (*RenderDrawListsFn)(ImDrawData* data); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a69374de..8d50ee8b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -443,7 +443,7 @@ void ImGui::ShowTestWindow(bool* p_opened) static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); ImGui::Text("Password input"); - static char bufpass[64] = "password123"; + static char bufpass[64] = "password123"; ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank); @@ -454,7 +454,7 @@ void ImGui::ShowTestWindow(bool* p_opened) if (ImGui::TreeNode("Multi-line Text Input")) { static bool read_only = false; - static char text[1024*16] = + static char text[1024*16] = "/*\n" " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" " the hexadecimal encoding of one offending instruction,\n" @@ -816,7 +816,7 @@ void ImGui::ShowTestWindow(bool* p_opened) if (ImGui::TreeNode("Widgets Width")) { static float f = 0.0f; - ImGui::Text("PushItemWidth(100)"); + ImGui::Text("PushItemWidth(100)"); ImGui::SameLine(); ShowHelpMarker("Fixed width."); ImGui::PushItemWidth(100); ImGui::DragFloat("float##1", &f); @@ -996,8 +996,8 @@ void ImGui::ShowTestWindow(bool* p_opened) // Tree const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; - ImGui::Button("Button##1"); - ImGui::SameLine(0.0f, spacing); + ImGui::Button("Button##1"); + ImGui::SameLine(0.0f, spacing); if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data ImGui::AlignFirstTextHeightToWidgets(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). @@ -1006,8 +1006,8 @@ void ImGui::ShowTestWindow(bool* p_opened) if (tree_opened) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data // Bullet - ImGui::Button("Button##3"); - ImGui::SameLine(0.0f, spacing); + ImGui::Button("Button##3"); + ImGui::SameLine(0.0f, spacing); ImGui::BulletText("Bullet text"); ImGui::AlignFirstTextHeightToWidgets(); @@ -1086,7 +1086,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::PopStyleVar(2); float scroll_x_delta = 0.0f; ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; - ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine(); + ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine(); ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; if (scroll_x_delta != 0.0f) { @@ -1181,7 +1181,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Spacing(); ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); ImGui::Separator(); - // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. + // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. ImGui::PushID("foo"); @@ -1396,7 +1396,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell.\nThere's no storage of state per-cell."); if (node_opened) { - ImGui::Columns(2, "tree items"); + ImGui::Columns(2, "tree items"); ImGui::Separator(); if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn(); if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn(); @@ -1513,7 +1513,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Button("Holding me clears the\nthe keyboard capture flag"); if (ImGui::IsItemActive()) ImGui::CaptureKeyboardFromApp(false); - + ImGui::TreePop(); } @@ -1798,7 +1798,7 @@ static void ShowExampleAppCustomRendering(bool* opened) ImGui::Text("Primitives"); static float sz = 36.0f; static ImVec4 col = ImVec4(1.0f,1.0f,0.4f,1.0f); - ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); ImGui::ColorEdit3("Color", &col.x); { const ImVec2 p = ImGui::GetCursorScreenPos(); @@ -2305,7 +2305,7 @@ static void ShowExampleAppPropertyEditor(bool* opened) ImGui::AlignFirstTextHeightToWidgets(); ImGui::Text("my sailor is rich"); ImGui::NextColumn(); - if (opened) + if (opened) { static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; for (int i = 0; i < 8; i++) @@ -2338,7 +2338,7 @@ static void ShowExampleAppPropertyEditor(bool* opened) ImGui::TreePop(); } ImGui::PopID(); - } + } }; // Iterate dummy objects with dummy members (all the same data) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b82327c0..4ae42c31 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -202,7 +202,7 @@ void ImDrawList::UpdateTextureID() AddDrawCmd(); return; } - + // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; if (prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL) @@ -702,11 +702,11 @@ static void PathBezierToCasteljau(ImVector* path, float x1, float y1, fl { float dx = x4 - x1; float dy = y4 - y1; - float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); - float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); d2 = (d2 >= 0) ? d2 : -d2; d3 = (d3 >= 0) ? d3 : -d3; - if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy)) + if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy)) { path->push_back(ImVec2(x4, y4)); } @@ -719,8 +719,8 @@ static void PathBezierToCasteljau(ImVector* path, float x1, float y1, fl float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f; float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f; - PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1); - PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1); + PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1); + PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1); } } @@ -865,14 +865,14 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, PathFill(col); } -void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments) -{ +void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments) +{ if ((col >> 24) == 0) return; - PathLineTo(pos0); - PathBezierCurveTo(cp0, cp1, pos1, num_segments); - PathStroke(col, false, thickness); + PathLineTo(pos0); + PathBezierCurveTo(cp0, cp1, pos1, num_segments); + PathStroke(col, false, thickness); } void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) @@ -1135,7 +1135,7 @@ static unsigned int stb_decompress_length(unsigned char *input); static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length); static const char* GetDefaultCompressedFontDataTTFBase85(); static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } -static void Decode85(const unsigned char* src, unsigned char* dst) +static void Decode85(const unsigned char* src, unsigned char* dst) { while (*src) { diff --git a/imgui_internal.h b/imgui_internal.h index 554ef885..841305ba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -707,7 +707,7 @@ namespace ImGui IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); - IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); + IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_existing_clip_rect = true); From 7661b1e778a68eaffc1ced1f4de0773b140bc0a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 26 Mar 2016 15:43:45 +0100 Subject: [PATCH 045/400] Trim trailing spaces --- examples/allegro5_example/imgui_impl_a5.cpp | 36 +++++++++---------- examples/allegro5_example/main.cpp | 8 ++--- examples/directx10_example/main.cpp | 2 +- .../directx11_example/imgui_impl_dx11.cpp | 4 +-- examples/directx11_example/main.cpp | 2 +- examples/directx9_example/imgui_impl_dx9.cpp | 22 ++++++------ .../imgui_impl_marmalade.cpp | 26 +++++++------- examples/opengl_example/imgui_impl_glfw.cpp | 2 +- examples/sdl_opengl3_example/main.cpp | 2 +- .../sdl_opengl_example/imgui_impl_sdl.cpp | 6 ++-- examples/sdl_opengl_example/main.cpp | 2 +- 11 files changed, 56 insertions(+), 56 deletions(-) diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index a4cce9fd..9af4ee0e 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -40,14 +40,14 @@ void ImGui_ImplA5_RenderDrawLists(ImDrawData* draw_data) al_get_blender(&op, &src, &dst); al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); - for (int n = 0; n < draw_data->CmdListsCount; n++) + 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 static ImVector vertices; vertices.resize(cmd_list->VtxBuffer.size()); - for (int i = 0; i < cmd_list->VtxBuffer.size(); ++i) + for (int i = 0; i < cmd_list->VtxBuffer.size(); ++i) { const ImDrawVert &dv = cmd_list->VtxBuffer[i]; ImDrawVertAllegro v; @@ -62,18 +62,18 @@ void ImGui_ImplA5_RenderDrawLists(ImDrawData* draw_data) // You can also use '#define ImDrawIdx unsigned int' in imconfig.h and request ImGui to output 32-bit indices static ImVector indices; indices.resize(cmd_list->IdxBuffer.size()); - for (int i = 0; i < cmd_list->IdxBuffer.size(); ++i) + for (int i = 0; i < cmd_list->IdxBuffer.size(); ++i) indices[i] = (int)cmd_list->IdxBuffer.Data[i]; int idx_offset = 0; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback) + if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); } - else + 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); @@ -104,11 +104,11 @@ bool Imgui_ImplA5_CreateDeviceObjects() ALLEGRO_BITMAP* img = al_create_bitmap(width, height); al_set_new_bitmap_flags(flags); al_set_new_bitmap_format(fmt); - if (!img) + if (!img) return false; ALLEGRO_LOCKED_REGION *locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY); - if (!locked_img) + if (!locked_img) { al_destroy_bitmap(img); return false; @@ -119,7 +119,7 @@ bool Imgui_ImplA5_CreateDeviceObjects() // Convert software texture to hardware texture. ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img); al_destroy_bitmap(img); - if (!cloned_img) + if (!cloned_img) return false; // Store our identifier @@ -137,7 +137,7 @@ bool Imgui_ImplA5_CreateDeviceObjects() void ImGui_ImplA5_InvalidateDeviceObjects() { - if (g_Texture) + if (g_Texture) { al_destroy_bitmap(g_Texture); ImGui::GetIO().Fonts->TexID = NULL; @@ -153,11 +153,11 @@ void ImGui_ImplA5_InvalidateDeviceObjects() bool ImGui_ImplA5_Init(ALLEGRO_DISPLAY* display) { g_Display = display; - - // Create custom vertex declaration. + + // Create custom vertex declaration. // Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats. // We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion. - ALLEGRO_VERTEX_ELEMENT elems[] = + ALLEGRO_VERTEX_ELEMENT elems[] = { { ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, OFFSETOF(ImDrawVertAllegro, pos) }, { ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, OFFSETOF(ImDrawVertAllegro, uv) }, @@ -205,13 +205,13 @@ bool ImGui_ImplA5_ProcessEvent(ALLEGRO_EVENT *ev) { ImGuiIO &io = ImGui::GetIO(); - switch (ev->type) + switch (ev->type) { case ALLEGRO_EVENT_MOUSE_AXES: io.MouseWheel += ev->mouse.dz; return true; case ALLEGRO_EVENT_KEY_CHAR: - if (ev->keyboard.display == g_Display) + if (ev->keyboard.display == g_Display) if (ev->keyboard.unichar > 0 && ev->keyboard.unichar < 0x10000) io.AddInputCharacter((unsigned short)ev->keyboard.unichar); return true; @@ -227,7 +227,7 @@ bool ImGui_ImplA5_ProcessEvent(ALLEGRO_EVENT *ev) void ImGui_ImplA5_NewFrame() { - if (!g_Texture) + if (!g_Texture) Imgui_ImplA5_CreateDeviceObjects(); ImGuiIO &io = ImGui::GetIO(); @@ -251,12 +251,12 @@ void ImGui_ImplA5_NewFrame() io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR); ALLEGRO_MOUSE_STATE mouse; - if (keys.display == g_Display) + if (keys.display == g_Display) { al_get_mouse_state(&mouse); io.MousePos = ImVec2((float)mouse.x, (float)mouse.y); } - else + else { io.MousePos = ImVec2(-1, -1); } diff --git a/examples/allegro5_example/main.cpp b/examples/allegro5_example/main.cpp index ee89c7cb..a8cd156b 100644 --- a/examples/allegro5_example/main.cpp +++ b/examples/allegro5_example/main.cpp @@ -9,7 +9,7 @@ int main(int, char**) { - // Setup Allegro + // Setup Allegro al_init(); al_install_keyboard(); al_install_mouse(); @@ -41,7 +41,7 @@ int main(int, char**) // Main loop bool running = true; - while (running) + while (running) { ALLEGRO_EVENT ev; while (al_get_next_event(queue, &ev)) @@ -70,7 +70,7 @@ int main(int, char**) } // 2. Show another simple window, this time using an explicit Begin/End pair - if (show_another_window) + if (show_another_window) { ImGui::SetNextWindowSize(ImVec2(200, 100), ImGuiSetCond_FirstUseEver); ImGui::Begin("Another Window", &show_another_window); @@ -79,7 +79,7 @@ int main(int, char**) } // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow() - if (show_test_window) + if (show_test_window) { ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver); ImGui::ShowTestWindow(&show_test_window); diff --git a/examples/directx10_example/main.cpp b/examples/directx10_example/main.cpp index 7d51327d..f47f9d5d 100644 --- a/examples/directx10_example/main.cpp +++ b/examples/directx10_example/main.cpp @@ -21,7 +21,7 @@ void CreateRenderTarget() g_pSwapChain->GetDesc(&sd); // Create the render target - ID3D10Texture2D* pBackBuffer; + ID3D10Texture2D* pBackBuffer; D3D10_RENDER_TARGET_VIEW_DESC render_target_view_desc; ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc)); render_target_view_desc.Format = sd.BufferDesc.Format; diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 2ac50c3c..8dd528d4 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -163,7 +163,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { const D3D11_RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId); - g_pd3dDeviceContext->RSSetScissorRects(1, &r); + g_pd3dDeviceContext->RSSetScissorRects(1, &r); g_pd3dDeviceContext->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); } idx_offset += pcmd->ElemCount; @@ -292,7 +292,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() // Create the vertex shader { - static const char* vertexShader = + static const char* vertexShader = "cbuffer vertexBuffer : register(b0) \ {\ float4x4 ProjectionMatrix; \ diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index 2b2e2ccf..d90f49c8 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -21,7 +21,7 @@ void CreateRenderTarget() g_pSwapChain->GetDesc(&sd); // Create the render target - ID3D11Texture2D* pBackBuffer; + ID3D11Texture2D* pBackBuffer; D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc; ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc)); render_target_view_desc.Format = sd.BufferDesc.Format; diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index eb6f68b4..21e8b5e3 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -97,8 +97,8 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); @@ -148,26 +148,26 @@ IMGUI_API LRESULT ImGui_ImplDX9_WndProcHandler(HWND, UINT msg, WPARAM wParam, LP io.MouseDown[0] = true; return true; case WM_LBUTTONUP: - io.MouseDown[0] = false; + io.MouseDown[0] = false; return true; case WM_RBUTTONDOWN: - io.MouseDown[1] = true; + io.MouseDown[1] = true; return true; case WM_RBUTTONUP: - io.MouseDown[1] = false; + io.MouseDown[1] = false; return true; case WM_MBUTTONDOWN: - io.MouseDown[2] = true; + io.MouseDown[2] = true; return true; case WM_MBUTTONUP: - io.MouseDown[2] = false; + io.MouseDown[2] = false; return true; case WM_MOUSEWHEEL: io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; return true; case WM_MOUSEMOVE: io.MousePos.x = (signed short)(lParam); - io.MousePos.y = (signed short)(lParam >> 16); + io.MousePos.y = (signed short)(lParam >> 16); return true; case WM_KEYDOWN: if (wParam < 256) @@ -191,7 +191,7 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) g_hWnd = (HWND)hwnd; g_pd3dDevice = device; - if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) + if (!QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) return false; if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) return false; @@ -244,7 +244,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8B8G8R8, D3DPOOL_DEFAULT, &g_FontTexture) < 0) return false; D3DLOCKED_RECT tex_locked_rect; - if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) + if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) return false; for (int y = 0; y < height; y++) memcpy((unsigned char *)tex_locked_rect.pBits + tex_locked_rect.Pitch * y, pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel)); @@ -301,7 +301,7 @@ void ImGui_ImplDX9_NewFrame() // Setup time step INT64 current_time; - QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); + QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; g_Time = current_time; diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index e1d68a78..f7cff9b1 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -13,7 +13,7 @@ #include "imgui_impl_marmalade.h" #include -#include +#include #include #include #include @@ -47,7 +47,7 @@ void ImGui_Marmalade_RenderDrawLists(ImDrawData* draw_data) CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert); CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert); - for( int i=0; i < nVert; i++ ) + for( int i=0; i < nVert; i++ ) { // TODO: optimize multiplication on gpu using vertex shader pVertStream[i].x = cmd_list->VtxBuffer[i].pos.x * g_scale.x; @@ -92,12 +92,12 @@ void ImGui_Marmalade_RenderDrawLists(ImDrawData* draw_data) static const char* ImGui_Marmalade_GetClipboardText() { - if (s3eClipboardAvailable()) + if (s3eClipboardAvailable()) { int size = s3eClipboardGetText(NULL, 0); - if (size > 0) + if (size > 0) { - if (g_ClipboardText) + if (g_ClipboardText) { delete[] g_ClipboardText; g_ClipboardText = NULL; @@ -124,7 +124,7 @@ int32 ImGui_Marmalade_PointerButtonEventCallback(void* SystemData, void* pUserDa // S3E_POINTER_BUTTON_SELECT s3ePointerEvent* pEvent = (s3ePointerEvent*)SystemData; - if (pEvent->m_Pressed == 1) + if (pEvent->m_Pressed == 1) { if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE) g_MousePressed[0] = true; @@ -149,7 +149,7 @@ int32 ImGui_Marmalade_KeyCallback(void* SystemData, void* userData) io.KeysDown[e->m_Key] = true; if (e->m_Pressed == 0) io.KeysDown[e->m_Key] = false; - + io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN; io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN; io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN; @@ -196,7 +196,7 @@ bool ImGui_Marmalade_CreateDeviceObjects() void ImGui_Marmalade_InvalidateDeviceObjects() { - if (g_ClipboardText) + if (g_ClipboardText) { delete[] g_ClipboardText; g_ClipboardText = NULL; @@ -278,8 +278,8 @@ void ImGui_Marmalade_NewFrame() mouse_x = s3ePointerGetX(); mouse_y = s3ePointerGetY(); io.MousePos = ImVec2((float)mouse_x/g_scale.x, (float)mouse_y/g_scale.y); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) - - for (int i = 0; i < 3; i++) + + for (int i = 0; i < 3; i++) { io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. g_MousePressed[i] = false; @@ -296,15 +296,15 @@ void ImGui_Marmalade_NewFrame() // Show/hide OSD keyboard if (io.WantTextInput) - { + { // Some text input widget is active? - if (!g_osdKeyboardEnabled) + if (!g_osdKeyboardEnabled) { g_osdKeyboardEnabled = true; s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 1); // show OSD keyboard } } - else + else { // No text input widget is active if (g_osdKeyboardEnabled) diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 335e4213..ae6f3115 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -265,7 +265,7 @@ void ImGui_ImplGlfw_NewFrame() { io.MousePos = ImVec2(-1,-1); } - + for (int i = 0; i < 3; i++) { io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. diff --git a/examples/sdl_opengl3_example/main.cpp b/examples/sdl_opengl3_example/main.cpp index 33b4903f..21cc8f2a 100644 --- a/examples/sdl_opengl3_example/main.cpp +++ b/examples/sdl_opengl3_example/main.cpp @@ -98,7 +98,7 @@ int main(int, char**) // Cleanup ImGui_ImplSdlGL3_Shutdown(); - SDL_GL_DeleteContext(glcontext); + SDL_GL_DeleteContext(glcontext); SDL_DestroyWindow(window); SDL_Quit(); diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index 927f8774..ba1746af 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -207,11 +207,11 @@ bool ImGui_ImplSdl_Init(SDL_Window* window) io.KeyMap[ImGuiKey_X] = SDLK_x; io.KeyMap[ImGuiKey_Y] = SDLK_y; io.KeyMap[ImGuiKey_Z] = SDLK_z; - + io.RenderDrawListsFn = ImGui_ImplSdl_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.SetClipboardTextFn = ImGui_ImplSdl_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSdl_GetClipboardText; - + #ifdef _WIN32 SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); @@ -257,7 +257,7 @@ void ImGui_ImplSdl_NewFrame(SDL_Window *window) io.MousePos = ImVec2((float)mx, (float)my); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) else io.MousePos = ImVec2(-1,-1); - + io.MouseDown[0] = g_MousePressed[0] || (mouseMask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. io.MouseDown[1] = g_MousePressed[1] || (mouseMask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; io.MouseDown[2] = g_MousePressed[2] || (mouseMask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; diff --git a/examples/sdl_opengl_example/main.cpp b/examples/sdl_opengl_example/main.cpp index fffab05b..e9574e2f 100644 --- a/examples/sdl_opengl_example/main.cpp +++ b/examples/sdl_opengl_example/main.cpp @@ -95,7 +95,7 @@ int main(int, char**) // Cleanup ImGui_ImplSdl_Shutdown(); - SDL_GL_DeleteContext(glcontext); + SDL_GL_DeleteContext(glcontext); SDL_DestroyWindow(window); SDL_Quit(); From cfbf06e3943259f10c87c81cdc6e940ff1f0d4c3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Mar 2016 10:38:14 +0200 Subject: [PATCH 046/400] Comments and moved EndFrame() for imgui_internal.h (for clarity? or extra confusion?) --- imgui.cpp | 12 +++++++----- imgui.h | 11 ++++++----- imgui_internal.h | 2 -- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 52348a12..d7aa1cf6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -79,6 +79,7 @@ - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. - call and read ImGui::ShowTestWindow() for demo code demonstrating most features. - see examples/ folder for standalone sample applications. Prefer reading examples/opengl_example/ first at it is the simplest. + you may be able to grab and copy a ready made imgui_impl_*** file from the examples/. - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). - getting started: @@ -86,12 +87,13 @@ - init: call io.Fonts->GetTexDataAsRGBA32(...) and load the font texture pixels into graphics memory. - every frame: 1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the fields marked 'Input' - 2/ call ImGui::NewFrame(). + 2/ call ImGui::NewFrame() as early as you can! 3/ use any ImGui function you want between NewFrame() and Render() - 4/ call ImGui::Render() to render all the accumulated command-lists. it will call your RenderDrawListFn handler that you set in the IO structure. + 4/ call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your RenderDrawListFn handler that you set in the IO structure. + (if you don't need to render, you still need to call Render() and ignore the callback, or call EndFrame() instead. if you call neither some aspects of windows focusing/moving will appear broken.) - all rendering information are stored into command-lists until ImGui::Render() is called. - - ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you must provide. - - effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases. + - ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide. + - effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases of your own application. - refer to the examples applications in the examples/ folder for instruction on how to setup your code. - a typical application skeleton may be: @@ -135,7 +137,7 @@ // 4) render & swap video buffers ImGui::Render(); - // swap video buffer, etc. + SwapBuffers(); } - after calling ImGui::NewFrame() you can read back flags from the IO structure to tell how ImGui intends to use your inputs. diff --git a/imgui.h b/imgui.h index 3b1ab1ed..5335a38c 100644 --- a/imgui.h +++ b/imgui.h @@ -103,14 +103,15 @@ namespace ImGui // Main IMGUI_API ImGuiIO& GetIO(); IMGUI_API ImGuiStyle& GetStyle(); - IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your io.RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame(). - IMGUI_API void NewFrame(); - IMGUI_API void Render(); // finalize rendering data, then call your io.RenderDrawListsFn() function if set. + IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your io.RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame() + IMGUI_API void NewFrame(); // start a new ImGui frame, you can submit any command from this point until NewFrame()/Render(). + IMGUI_API void EndFrame(); // ends the ImGui frame. automatically called by Render()! + IMGUI_API void Render(); // ends the ImGui frame, finalize rendering data, then call your io.RenderDrawListsFn() function if set. IMGUI_API void Shutdown(); IMGUI_API void ShowUserGuide(); // help block IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block - IMGUI_API void ShowTestWindow(bool* opened = NULL); // test window, demonstrate ImGui features - IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window for debugging imgui + IMGUI_API void ShowTestWindow(bool* opened = NULL); // test window demonstrating ImGui features + IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window for debugging ImGui // Window IMGUI_API bool Begin(const char* name, bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). diff --git a/imgui_internal.h b/imgui_internal.h index 841305ba..9c42da07 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -683,8 +683,6 @@ namespace ImGui IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); - IMGUI_API void EndFrame(); // Automatically called by Render() - 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); IMGUI_API bool ItemAdd(const ImRect& bb, const ImGuiID* id); From c4876078b4a981d9d8cd652ee67caa30bcdf5f46 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Mar 2016 11:43:12 +0200 Subject: [PATCH 047/400] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 030cee98..ff22aaf2 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,9 @@ Gallery See the [Screenshots Thread](https://github.com/ocornut/imgui/issues/123) for some user creations. -![screenshot 1](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/examples_04.png) +![screenshot 1](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_01.png) +![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_02.png) + ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_01.png) ![screenshot 3](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_02.png) ![screenshot 4](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_03.png) From 41c5d4651b15d427e814144758d8ad75a92fa5c9 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 27 Mar 2016 12:04:17 +0200 Subject: [PATCH 048/400] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ff22aaf2..ce47a092 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,8 @@ See the [Screenshots Thread](https://github.com/ocornut/imgui/issues/123) for so ![screenshot 1](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_01.png) ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_02.png) +[![profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler-880.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler.png) + ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_01.png) ![screenshot 3](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_02.png) ![screenshot 4](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_03.png) From ae0c33c98368b5401e06aab4b1c2d6579e976e2c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Mar 2016 11:33:23 +0200 Subject: [PATCH 049/400] Examples: Links --- examples/README.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/README.txt b/examples/README.txt index b80866c1..f8e0c55e 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -1,5 +1,10 @@ Those are standalone ready-to-build applications to demonstrate ImGui. -Binaries of some of those demos are available at http://www.miracleworld.net/imgui/binaries +Binaries of some of those demos: http://www.miracleworld.net/imgui/binaries + +Third party languages and frameworks bindings: https://github.com/ocornut/imgui/wiki/Links +(languages: C, .net, rust, D, Python, Lua..) +(frameworks: DX12, Vulkan, Cinder, OpenGLES, openFrameworks, Cocos2d-x, SFML, Flexium, NanoRT, Irrlicht..) +(extras: RemoteImGui, ImWindow, imgui_wm..) TL;DR; - Newcomers, read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup ImGui in your codebase. From 171b0e5ca96fcb9721f4c62bfb607a6a0f51a0ff Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 30 Mar 2016 16:30:17 +0200 Subject: [PATCH 050/400] Update README.md --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ce47a092..0311fbb4 100644 --- a/README.md +++ b/README.md @@ -162,13 +162,16 @@ Embeds [stb_textedit.h, stb_truetype.h, stb_rectpack.h](https://github.com/nothi Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. And everybody posting feedback, questions and patches on the GitHub. -ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). +Ongoing ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). -Special supporters: -- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano. +Double-chocolate sponsors: +- Media Molecule -And: -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm. +Salty caramel supporters: +- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima, + +Caramel supporters: +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts. And other supporters; thanks! From a6399f120fc7ed5b6fe20640f8c765ea158dec22 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 18:22:40 +0200 Subject: [PATCH 051/400] IO: Added "Super" keyboard modifiers (corresponding to Cmd on Mac and Windows key in theory although the later is hard to read) (#473) NB: Value not used. --- examples/allegro5_example/imgui_impl_a5.cpp | 1 + .../directx10_example/imgui_impl_dx10.cpp | 1 + .../directx11_example/imgui_impl_dx11.cpp | 1 + examples/directx9_example/imgui_impl_dx9.cpp | 1 + .../ios_example/imguiex/imgui_impl_ios.mm | 8 +-- .../imgui_impl_marmalade.cpp | 1 + .../opengl3_example/imgui_impl_glfw_gl3.cpp | 1 + examples/opengl_example/imgui_impl_glfw.cpp | 1 + .../imgui_impl_sdl_gl3.cpp | 53 ++++++++++--------- .../sdl_opengl_example/imgui_impl_sdl.cpp | 1 + imgui.h | 1 + imgui_demo.cpp | 2 +- 12 files changed, 41 insertions(+), 31 deletions(-) diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index 9af4ee0e..c7ba1106 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -249,6 +249,7 @@ void ImGui_ImplA5_NewFrame() io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL); io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT); io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR); + io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN); ALLEGRO_MOUSE_STATE mouse; if (keys.display == g_Display) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 73bd3abf..21f86f5d 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -496,6 +496,7 @@ void ImGui_ImplDX10_NewFrame() io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; io.KeyAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events // io.MousePos : filled by WM_MOUSEMOVE events // io.MouseDown : filled by WM_*BUTTON* events diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 8dd528d4..8451fb8e 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -494,6 +494,7 @@ void ImGui_ImplDX11_NewFrame() io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; io.KeyAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events // io.MousePos : filled by WM_MOUSEMOVE events // io.MouseDown : filled by WM_*BUTTON* events diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 21e8b5e3..17f4f078 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -309,6 +309,7 @@ void ImGui_ImplDX9_NewFrame() io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; io.KeyAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; // io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events // io.MousePos : filled by WM_MOUSEMOVE events // io.MouseDown : filled by WM_*BUTTON* events diff --git a/examples/ios_example/imguiex/imgui_impl_ios.mm b/examples/ios_example/imguiex/imgui_impl_ios.mm index ab3fcd87..b286c4d4 100644 --- a/examples/ios_example/imguiex/imgui_impl_ios.mm +++ b/examples/ios_example/imguiex/imgui_impl_ios.mm @@ -263,10 +263,10 @@ void ImGui_KeyboardCallback(uSynergyCookie cookie, uint16_t key, // printf("Synergy: keyboard callback: 0x%02X (%s)", scanCode, down?"true":"false"); ImGuiIO& io = ImGui::GetIO(); io.KeysDown[key] = down; - io.KeyShift = modifiers & USYNERGY_MODIFIER_SHIFT; - io.KeyCtrl = modifiers & USYNERGY_MODIFIER_CTRL; - io.KeyAlt = modifiers & USYNERGY_MODIFIER_ALT; - + io.KeyShift = (modifiers & USYNERGY_MODIFIER_SHIFT); + io.KeyCtrl = (modifiers & USYNERGY_MODIFIER_CTRL); + io.KeyAlt = (modifiers & USYNERGY_MODIFIER_ALT); + io.KeySuper = (modifiers & USYNERGY_MODIFIER_WIN); // Add this as keyboard input if ((down) && (key) && (scanCode<256) && !(modifiers & USYNERGY_MODIFIER_CTRL)) diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index f7cff9b1..12d5dfaa 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -153,6 +153,7 @@ int32 ImGui_Marmalade_KeyCallback(void* SystemData, void* userData) io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN; io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN; io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN; + io.KeySuper = s3eKeyboardGetState(s3eKeyLeftWindows) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightWindows) == S3E_KEY_STATE_DOWN; return 0; } diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 7cad27b0..b1d2a40b 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -157,6 +157,7 @@ void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mo io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; } void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c) diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index ae6f3115..fd9ce720 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -139,6 +139,7 @@ void ImGui_ImplGlFw_KeyCallback(GLFWwindow*, int key, int, int action, int mods) io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; } void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 7afbf343..5406f424 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -134,36 +134,37 @@ bool ImGui_ImplSdlGL3_ProcessEvent(SDL_Event* event) switch (event->type) { case SDL_MOUSEWHEEL: - { - if (event->wheel.y > 0) - g_MouseWheel = 1; - if (event->wheel.y < 0) - g_MouseWheel = -1; - return true; - } + { + if (event->wheel.y > 0) + g_MouseWheel = 1; + if (event->wheel.y < 0) + g_MouseWheel = -1; + return true; + } case SDL_MOUSEBUTTONDOWN: - { - if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true; - if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true; - if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true; - return true; - } + { + if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true; + if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true; + if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true; + return true; + } case SDL_TEXTINPUT: - { - ImGuiIO& io = ImGui::GetIO(); - io.AddInputCharactersUTF8(event->text.text); - return true; - } + { + ImGuiIO& io = ImGui::GetIO(); + io.AddInputCharactersUTF8(event->text.text); + return true; + } case SDL_KEYDOWN: case SDL_KEYUP: - { - int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK; - io.KeysDown[key] = (event->type == SDL_KEYDOWN); - io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); - io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); - io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); - return true; - } + { + int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK; + io.KeysDown[key] = (event->type == SDL_KEYDOWN); + io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); + io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); + io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); + io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); + return true; + } } return false; } diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index ba1746af..0d885b07 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -143,6 +143,7 @@ bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event) io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); + io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); return true; } } diff --git a/imgui.h b/imgui.h index 5335a38c..33fe4c6c 100644 --- a/imgui.h +++ b/imgui.h @@ -743,6 +743,7 @@ struct ImGuiIO bool KeyCtrl; // Keyboard modifier pressed: Control bool KeyShift; // Keyboard modifier pressed: Shift bool KeyAlt; // Keyboard modifier pressed: Alt + bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows bool KeysDown[512]; // Keyboard keys that are pressed (in whatever storage order you naturally have access to keyboard data) ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8d50ee8b..f85eda53 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1500,7 +1500,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); } ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } - ImGui::Text("KeyMods: %s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : ""); + ImGui::Text("KeyMods: %s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("WantCaptureMouse: %s", io.WantCaptureMouse ? "true" : "false"); ImGui::Text("WantCaptureKeyboard: %s", io.WantCaptureKeyboard ? "true" : "false"); From 587fc60f255b8ec3c9ce15ac946c4bc6090d94e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 18:57:08 +0200 Subject: [PATCH 052/400] InputText/IO: Added WordMovementUsesAltKey , ShortcutsUseSuperKey for OS X Compatible behavior (#473) --- imgui.cpp | 27 ++++++++++++++++++--------- imgui.h | 4 ++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d7aa1cf6..feff82b0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -787,6 +787,12 @@ ImGuiIO::ImGuiIO() GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; + + // Set OS X style defaults based on __APPLE__ compile time flag +#ifdef __APPLE__ + WordMovementUsesAltKey = true; // Text editing cursor movement using Alt instead of Ctrl + ShortcutsUseSuperKey = true; // Shortcuts using Cmd/Super instead of Ctrl +#endif } // Pass in translated ASCII characters for text input. @@ -7320,6 +7326,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_ctrl_down = io.KeyCtrl; const bool is_shift_down = io.KeyShift; const bool is_alt_down = io.KeyAlt; + const bool is_super_down = io.KeySuper; const bool focus_requested = FocusableItemRegister(window, g.ActiveId == id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent); const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; @@ -7449,9 +7456,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Handle various key-presses bool cancel_edit = false; const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); - const bool is_ctrl_only = is_ctrl_down && !is_alt_down && !is_shift_down; - if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } + const bool is_shortcutkey_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down)); + const bool is_wordmove_key_down = (io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl); + + if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y - g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); } else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); } else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } @@ -7479,11 +7488,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (InputTextFilterCharacter(&c, flags, callback, user_data)) edit_state.OnKeyPressed((int)c); } - else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; } - else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } - else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } - else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } - else if (is_ctrl_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) + else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; } + else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } + else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } + else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } + else if (is_shortcutkey_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) { // Cut, Copy const bool cut = IsKeyPressedMap(ImGuiKey_X); @@ -7505,7 +7514,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 stb_textedit_cut(&edit_state, &edit_state.StbState); } } - else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) + else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) { // Paste if (g.IO.GetClipboardTextFn) diff --git a/imgui.h b/imgui.h index 33fe4c6c..714cc9b8 100644 --- a/imgui.h +++ b/imgui.h @@ -708,6 +708,10 @@ struct ImGuiIO ImVec2 DisplayVisibleMin; // (0.0f,0.0f) // If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area. ImVec2 DisplayVisibleMax; // (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize + // Advanced/subtle behaviors + bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl + bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl + //------------------------------------------------------------------ // User Functions //------------------------------------------------------------------ From aa7a29cdbf7a45f73f12d11987e19ee088d5cccb Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 18:57:50 +0200 Subject: [PATCH 053/400] InputText(): Added io.DoubleClickSelectsWord option for OS X compatible behavior (#473) --- imgui.cpp | 9 ++++++++- imgui.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index feff82b0..757d405d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -792,6 +792,7 @@ ImGuiIO::ImGuiIO() #ifdef __APPLE__ WordMovementUsesAltKey = true; // Text editing cursor movement using Alt instead of Ctrl ShortcutsUseSuperKey = true; // Shortcuts using Cmd/Super instead of Ctrl + DoubleClickSelectsWord = true; // Double click selects by word instead of selecting whole text #endif } @@ -7414,11 +7415,17 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const float mouse_x = (g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; const float mouse_y = (is_multiline ? (g.IO.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); - if (select_all || (hovered && io.MouseDoubleClicked[0])) + if (select_all || (hovered && !io.DoubleClickSelectsWord && io.MouseDoubleClicked[0])) { edit_state.SelectAll(); edit_state.SelectedAllMouseLock = true; } + else if (hovered && io.DoubleClickSelectsWord && io.MouseDoubleClicked[0]) + { + // Select a word only, OS X style (by simulating keystrokes) + edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + } else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock) { stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y); diff --git a/imgui.h b/imgui.h index 714cc9b8..0d8a4d2c 100644 --- a/imgui.h +++ b/imgui.h @@ -711,6 +711,7 @@ struct ImGuiIO // Advanced/subtle behaviors bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl + bool DoubleClickSelectsWord; // = defined(__APPLE__) // OS X style: Double click selects by word instead of selecting whole text //------------------------------------------------------------------ // User Functions From f48fc51777291bbe44b88fe4a936744000f39613 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 18:58:42 +0200 Subject: [PATCH 054/400] IO: Added unused MultiSelectUsesSuperKey dummy field to convey semantic for OS X compatible behavior (#473) --- imgui.cpp | 7 ++++--- imgui.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 757d405d..37dadd83 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -790,9 +790,10 @@ ImGuiIO::ImGuiIO() // Set OS X style defaults based on __APPLE__ compile time flag #ifdef __APPLE__ - WordMovementUsesAltKey = true; // Text editing cursor movement using Alt instead of Ctrl - ShortcutsUseSuperKey = true; // Shortcuts using Cmd/Super instead of Ctrl - DoubleClickSelectsWord = true; // Double click selects by word instead of selecting whole text + WordMovementUsesAltKey = true; // OS X style: Text editing cursor movement using Alt instead of Ctrl + ShortcutsUseSuperKey = true; // OS X style: Shortcuts using Cmd/Super instead of Ctrl + DoubleClickSelectsWord = true; // OS X style: Double click selects by word instead of selecting whole text + MultiSelectUsesSuperKey = true; // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl #endif } diff --git a/imgui.h b/imgui.h index 0d8a4d2c..2c1877e5 100644 --- a/imgui.h +++ b/imgui.h @@ -712,6 +712,7 @@ struct ImGuiIO bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl bool DoubleClickSelectsWord; // = defined(__APPLE__) // OS X style: Double click selects by word instead of selecting whole text + bool MultiSelectUsesSuperKey; // = defined(__APPLE__) // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl [unused yet] //------------------------------------------------------------------ // User Functions From e7b95646b92b0e28c75595678af51d89ad9c2aee Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 20:08:11 +0200 Subject: [PATCH 055/400] stb_textedit.h updated to 1.8 (our two main changes were merged now) --- stb_textedit.h | 88 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/stb_textedit.h b/stb_textedit.h index 1d42862d..29af484b 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,8 +1,4 @@ -// [ImGui] this is a slightly modified version of stb_truetype.h 1.4 -// [ImGui] we made a fix for using the END key on multi-line text edit, see https://github.com/ocornut/imgui/issues/275 -// [ImGui] we made a fix for using keyboard while using mouse, see https://github.com/nothings/stb/pull/209 - -// stb_textedit.h - v1.4 - public domain - Sean Barrett +// stb_textedit.h - v1.8 - public domain - Sean Barrett // Development of this library was sponsored by RAD Game Tools // // This C header file implements the guts of a multi-line text-editing @@ -21,19 +17,24 @@ // // LICENSE // -// This software has been placed in the public domain by its author. -// Where that dedication is not recognized, you are granted a perpetual, -// irrevocable license to copy and modify this file as you see fit. +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. // // // DEPENDENCIES // -// Uses the C runtime function 'memmove'. Uses no other functions. -// Performs no runtime allocations. +// Uses the C runtime function 'memmove', which you can override +// by defining STB_TEXTEDIT_memmove before the implementation. +// Uses no other functions. Performs no runtime allocations. // // // VERSION HISTORY // +// 1.8 (2016-04-02) better keyboard handling when mouse button is down +// 1.7 (2015-09-13) change y range handling in case baseline is non-0 +// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove +// 1.5 (2014-09-10) add support for secondary keys for OS X // 1.4 (2014-08-17) fix signed/unsigned warnings // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary // 1.2 (2014-05-27) fix some RAD types that had crept into the new code @@ -46,7 +47,13 @@ // ADDITIONAL CONTRIBUTORS // // Ulf Winklemann: move-by-word in 1.1 -// Scott Graham: mouse selection bugfix in 1.3 +// Fabian Giesen: secondary key inputs in 1.5 +// Martins Mozeiko: STB_TEXTEDIT_memmove +// +// Bugfixes: +// Scott Graham +// Daniel Keller +// Omar Cornut // // USAGE // @@ -146,6 +153,10 @@ // required for WORDLEFT/WORDRIGHT // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT +// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line +// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line +// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text +// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // // Todo: // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page @@ -356,7 +367,10 @@ typedef struct // included just the "header" portion #ifdef STB_TEXTEDIT_IMPLEMENTATION -#include // memmove +#ifndef STB_TEXTEDIT_memmove +#include +#define STB_TEXTEDIT_memmove memmove +#endif ///////////////////////////////////////////////////////////////////////////// @@ -372,9 +386,6 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) float base_y = 0, prev_x; int i=0, k; - if (y < 0) - return 0; - r.x0 = r.x1 = 0; r.ymin = r.ymax = 0; r.num_chars = 0; @@ -385,6 +396,9 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) if (r.num_chars <= 0) return n; + if (i==0 && y < base_y + r.ymin) + return 0; + if (y < base_y + r.ymax) break; @@ -923,23 +937,35 @@ retry: state->has_preferred_x = 0; break; +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2: +#endif case STB_TEXTEDIT_K_TEXTSTART: state->cursor = state->select_start = state->select_end = 0; state->has_preferred_x = 0; break; +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2: +#endif case STB_TEXTEDIT_K_TEXTEND: state->cursor = STB_TEXTEDIT_STRINGLEN(str); state->select_start = state->select_end = 0; state->has_preferred_x = 0; break; +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: +#endif case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: stb_textedit_prep_selection_at_cursor(state); state->cursor = state->select_end = 0; state->has_preferred_x = 0; break; +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: +#endif case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: stb_textedit_prep_selection_at_cursor(state); state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); @@ -947,6 +973,9 @@ retry: break; +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2: +#endif case STB_TEXTEDIT_K_LINESTART: { StbFindState find; stb_textedit_clamp(str, state); @@ -957,18 +986,25 @@ retry: break; } +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2: +#endif case STB_TEXTEDIT_K_LINEEND: { StbFindState find; stb_textedit_clamp(str, state); stb_textedit_move_to_first(state); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + state->has_preferred_x = 0; state->cursor = find.first_char + find.length; if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) - state->cursor--; - state->has_preferred_x = 0; + --state->cursor; break; } +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: +#endif case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: { StbFindState find; stb_textedit_clamp(str, state); @@ -979,15 +1015,19 @@ retry: break; } +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: +#endif case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { StbFindState find; stb_textedit_clamp(str, state); stb_textedit_prep_selection_at_cursor(state); stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - state->cursor = state->select_end = find.first_char + find.length; - if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) - state->cursor = state->select_end = state->cursor - 1; state->has_preferred_x = 0; + state->cursor = find.first_char + find.length; + if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->select_end = state->cursor; break; } @@ -1018,13 +1058,13 @@ static void stb_textedit_discard_undo(StbUndoState *state) int n = state->undo_rec[0].insert_length, i; // delete n characters from all other records state->undo_char_point = state->undo_char_point - (short) n; // vsnet05 - memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); + STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); for (i=0; i < state->undo_point; ++i) if (state->undo_rec[i].char_storage >= 0) state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it } --state->undo_point; - memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0]))); + STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); } } @@ -1042,13 +1082,13 @@ static void stb_textedit_discard_redo(StbUndoState *state) int n = state->undo_rec[k].insert_length, i; // delete n characters from all other records state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 - memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); + STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); for (i=state->redo_point; i < k; ++i) if (state->undo_rec[i].char_storage >= 0) state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 } ++state->redo_point; - memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); + STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); } } From c3376cd45c72c6932300683e91091c3e2bfb82f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 20:08:42 +0200 Subject: [PATCH 056/400] stb_textedit.h Local warning fixes --- stb_textedit.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/stb_textedit.h b/stb_textedit.h index 29af484b..63476ad4 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,3 +1,6 @@ +// [ImGui] this is a slightly modified version of stb_truetype.h 1.8 +// [ImGui] - fixed some minor warnings + // stb_textedit.h - v1.8 - public domain - Sean Barrett // Development of this library was sponsored by RAD Game Tools // @@ -1058,13 +1061,13 @@ static void stb_textedit_discard_undo(StbUndoState *state) int n = state->undo_rec[0].insert_length, i; // delete n characters from all other records state->undo_char_point = state->undo_char_point - (short) n; // vsnet05 - STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); + STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); for (i=0; i < state->undo_point; ++i) if (state->undo_rec[i].char_storage >= 0) state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it } --state->undo_point; - STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); + STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0]))); } } @@ -1082,13 +1085,13 @@ static void stb_textedit_discard_redo(StbUndoState *state) int n = state->undo_rec[k].insert_length, i; // delete n characters from all other records state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 - STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); + STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); for (i=state->redo_point; i < k; ++i) if (state->undo_rec[i].char_storage >= 0) state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 } ++state->redo_point; - STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); + STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); } } From 9945eecaf4c9e9523039d61d288b51d86e9977e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 20:12:20 +0200 Subject: [PATCH 057/400] stb_truetype: updated 1.08 > 1.10 + minor unused variable warning fix --- stb_truetype.h | 91 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 1f93135b..e6dae975 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v1.08 - public domain +// stb_truetype.h - v1.10 - public domain // authored from 2009-2015 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: @@ -21,6 +21,10 @@ // Mikko Mononen: compound shape support, more cmap formats // Tor Andersson: kerning, subpixel rendering // +// Misc other: +// Ryan Gordon +// Simon Glass +// // Bug/warning reports/fixes: // "Zer" on mollyrocket (with fix) // Cass Everitt @@ -42,12 +46,13 @@ // Sergey Popov // Giumo X. Clanjor // Higor Euripedes -// -// Misc other: -// Ryan Gordon +// Thomas Fields +// Derek Vinyard // // VERSION HISTORY // +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; // variant PackFontRanges to pack and render in separate phases; @@ -65,9 +70,9 @@ // // LICENSE // -// This software is in the public domain. Where that dedication is not -// recognized, you are granted a perpetual, irrevocable license to copy, -// distribute, and modify this file as you see fit. +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. // // USAGE // @@ -403,6 +408,11 @@ int main(int arg, char **argv) #define STBTT_sqrt(x) sqrt(x) #endif + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h #ifndef STBTT_malloc #include @@ -626,7 +636,7 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // The following structure is defined publically so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. -typedef struct stbtt_fontinfo +struct stbtt_fontinfo { void * userdata; unsigned char * data; // pointer to .ttf file @@ -637,7 +647,7 @@ typedef struct stbtt_fontinfo int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf int index_map; // a cmap mapping for our chosen character encoding int indexToLocFormat; // format needed to map from glyph index to glyph -} stbtt_fontinfo; +}; STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); // Given an offset into the file that defines a font, this function builds @@ -1556,7 +1566,7 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) { - int x0,y0,x1,y1; + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { // e.g. space character if (ix0) *ix0 = 0; @@ -1672,6 +1682,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i { stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); if (!z) return z; // round dx down to avoid overshooting @@ -1693,6 +1704,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i { stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); //STBTT_assert(e->y0 <= start_point); if (!z) return z; z->fdx = dxdy; @@ -1817,21 +1829,23 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, while (e->y0 <= scan_y) { if (e->y1 > scan_y) { stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } } } ++e; @@ -1986,7 +2000,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, } y_crossing += dy * (x2 - (x1+1)); - STBTT_assert(fabs(area) <= 1.01f); + STBTT_assert(STBTT_fabs(area) <= 1.01f); scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing); @@ -2102,10 +2116,12 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, while (e->y0 <= scan_y_bottom) { if (e->y0 != e->y1) { stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); - STBTT_assert(z->ey >= scan_y_top); - // insert at front - z->next = active; - active = z; + if (z != NULL) { + STBTT_assert(z->ey >= scan_y_top); + // insert at front + z->next = active; + active = z; + } } ++e; } @@ -2121,7 +2137,7 @@ static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int m; sum += scanline2[i]; k = scanline[i] + sum; - k = (float) fabs(k)*255 + 0.5f; + k = (float) STBTT_fabs(k)*255 + 0.5f; m = (int) k; if (m > 255) m = 255; result->pixels[j*result->stride + i] = (unsigned char) m; @@ -2422,7 +2438,10 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info if (scale_x == 0) scale_x = scale_y; if (scale_y == 0) { - if (scale_x == 0) return NULL; + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } scale_y = scale_x; } @@ -2514,6 +2533,7 @@ STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // fo float scale; int x,y,bottom_y, i; stbtt_fontinfo f; + f.userdata = NULL; if (!stbtt_InitFont(&f, data, offset)) return -1; STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels @@ -2707,6 +2727,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i unsigned char buffer[STBTT_MAX_OVERSAMPLE]; int safe_w = w - kernel_width; int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze for (j=0; j < h; ++j) { int i; unsigned int total; @@ -2768,6 +2789,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i unsigned char buffer[STBTT_MAX_OVERSAMPLE]; int safe_h = h - kernel_width; int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze for (j=0; j < w; ++j) { int i; unsigned int total; @@ -2976,6 +2998,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd if (rects == NULL) return 0; + info.userdata = spc->user_allocator_context; stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); @@ -3193,6 +3216,10 @@ STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const // FULL VERSION HISTORY // +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges // 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; // allow PackFontRanges to pack and render in separate phases; From aeaf5ccebb259725551c87f577d7a47f2129a757 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 21:20:41 +0200 Subject: [PATCH 058/400] stb_textedit.h: proposal for upstream PR to allow custom move-left/move-right handlers (following #473) --- stb_textedit.h | 62 +++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/stb_textedit.h b/stb_textedit.h index 63476ad4..3c300325 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,5 +1,6 @@ // [ImGui] this is a slightly modified version of stb_truetype.h 1.8 // [ImGui] - fixed some minor warnings +// [ImGui] - added STB_TEXTEDIT_MOVEWORDLEFT/STB_TEXTEDIT_MOVEWORDRIGHT custom handler (#473) // stb_textedit.h - v1.8 - public domain - Sean Barrett // Development of this library was sponsored by RAD Game Tools @@ -151,15 +152,17 @@ // STB_TEXTEDIT_K_REDO keyboard input to perform redo // // Optional: -// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode -// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), -// required for WORDLEFT/WORDRIGHT -// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT -// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT -// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line -// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line -// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text -// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text +// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode +// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), +// required for default WORDLEFT/WORDRIGHT handlers +// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to +// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to +// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT +// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT +// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line +// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line +// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text +// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // // Todo: // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page @@ -618,9 +621,9 @@ static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx ) return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1; } -static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) +#ifndef STB_TEXTEDIT_MOVEWORDLEFT +static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, int c ) { - int c = _state->cursor - 1; while( c >= 0 && !is_word_boundary( _str, c ) ) --c; @@ -629,11 +632,13 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_Te return c; } +#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous +#endif -static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) +#ifndef STB_TEXTEDIT_MOVEWORDRIGHT +static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, int c ) { const int len = STB_TEXTEDIT_STRINGLEN(_str); - int c = _state->cursor+1; while( c < len && !is_word_boundary( _str, c ) ) ++c; @@ -642,6 +647,9 @@ static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_Texted return c; } +#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next +#endif + #endif // update selection and cursor to match each other @@ -763,21 +771,12 @@ retry: state->has_preferred_x = 0; break; -#ifdef STB_TEXTEDIT_IS_SPACE +#ifdef STB_TEXTEDIT_MOVEWORDLEFT case STB_TEXTEDIT_K_WORDLEFT: if (STB_TEXT_HAS_SELECTION(state)) stb_textedit_move_to_first(state); else { - state->cursor = stb_textedit_move_to_word_previous(str, state); - stb_textedit_clamp( str, state ); - } - break; - - case STB_TEXTEDIT_K_WORDRIGHT: - if (STB_TEXT_HAS_SELECTION(state)) - stb_textedit_move_to_last(str, state); - else { - state->cursor = stb_textedit_move_to_word_next(str, state); + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor-1); stb_textedit_clamp( str, state ); } break; @@ -786,17 +785,28 @@ retry: if( !STB_TEXT_HAS_SELECTION( state ) ) stb_textedit_prep_selection_at_cursor(state); - state->cursor = stb_textedit_move_to_word_previous(str, state); + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor-1); state->select_end = state->cursor; stb_textedit_clamp( str, state ); break; +#endif + +#ifdef STB_TEXTEDIT_MOVEWORDRIGHT + case STB_TEXTEDIT_K_WORDRIGHT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor+1); + stb_textedit_clamp( str, state ); + } + break; case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: if( !STB_TEXT_HAS_SELECTION( state ) ) stb_textedit_prep_selection_at_cursor(state); - state->cursor = stb_textedit_move_to_word_next(str, state); + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor+1); state->select_end = state->cursor; stb_textedit_clamp( str, state ); From c61e08e8c49116ef0a51c4b22df9671e5f11f74b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 2 Apr 2016 22:06:47 +0200 Subject: [PATCH 059/400] InputText: move to next word OS X style behavior on OS X (#473) --- imgui.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 37dadd83..406aa805 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7097,8 +7097,18 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -static bool is_separator(unsigned int c) { return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } -#define STB_TEXTEDIT_IS_SPACE(CH) ( ImCharIsSpace((unsigned int)CH) || is_separator((unsigned int)CH) ) +static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } +static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; } +static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +#ifdef __APPLE__ // FIXME: Move setting to IO structure +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +#else +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +#endif +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL + static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) { ImWchar* dst = obj->Text.Data + pos; From 1eacfd120b337cb9c93f37ba12e0e87d471b1e5b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 00:26:00 +0200 Subject: [PATCH 060/400] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0311fbb4..101cafc3 100644 --- a/README.md +++ b/README.md @@ -165,13 +165,13 @@ Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Bin Ongoing ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). Double-chocolate sponsors: -- Media Molecule +- Media Molecule, Mobigame Salty caramel supporters: -- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima, +- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima Caramel supporters: -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts. +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley. And other supporters; thanks! From d53c308852bf15237987111a9f33cc507a08a3fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 00:47:41 +0200 Subject: [PATCH 061/400] Moved EndFrame() back to imgui_internal.h + comments. Undo cfbf06e3943259f10c87c81cdc6e940ff1f0d4c3 --- imgui.h | 11 +++++------ imgui_internal.h | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui.h b/imgui.h index 2c1877e5..50b5f76a 100644 --- a/imgui.h +++ b/imgui.h @@ -105,7 +105,6 @@ namespace ImGui IMGUI_API ImGuiStyle& GetStyle(); IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your io.RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame() IMGUI_API void NewFrame(); // start a new ImGui frame, you can submit any command from this point until NewFrame()/Render(). - IMGUI_API void EndFrame(); // ends the ImGui frame. automatically called by Render()! IMGUI_API void Render(); // ends the ImGui frame, finalize rendering data, then call your io.RenderDrawListsFn() function if set. IMGUI_API void Shutdown(); IMGUI_API void ShowUserGuide(); // help block @@ -114,11 +113,11 @@ namespace ImGui IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window for debugging ImGui // Window - IMGUI_API bool Begin(const char* name, bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). - IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! maybe obsolete this API eventually. - IMGUI_API void End(); - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " + IMGUI_API bool Begin(const char* name, bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // push window to the stack and start appending to it. see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). + IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // ". this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. + IMGUI_API void End(); // finish appending to current window, pop it off the window stack. + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " IMGUI_API void EndChild(); IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() diff --git a/imgui_internal.h b/imgui_internal.h index 9c42da07..0f654a54 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -679,6 +679,8 @@ namespace ImGui IMGUI_API ImGuiWindow* FindWindowByName(const char* name); IMGUI_API void FocusWindow(ImGuiWindow* window); + IMGUI_API void EndFrame(); // Ends the ImGui frame. Automatically called by Render()! you most likely don't need to ever call that yourself directly. If you don't need to render you can call EndFrame() but you'll have wasted CPU already. If you don't need to render, don't create any windows instead! + IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); From 650515ce491089c447007fe9558d1122f4b9f8f2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 01:07:11 +0200 Subject: [PATCH 062/400] Updated todo list and comments --- imgui.cpp | 22 +++++++++++++--------- imgui.h | 3 ++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 406aa805..1a21e1d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -439,6 +439,7 @@ !- window: begin with *p_opened == false should return false. - window: get size/pos helpers given names (see discussion in #249) - window: a collapsed window can be stuck behind the main menu bar? + - window: when window is small, prioritize resize button over close button. - window: detect extra End() call that pop the "Debug" window out and assert at call site instead of later. - window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic. - window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd. @@ -448,15 +449,19 @@ - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. - widgets: clean up widgets internal toward exposing everything. - widgets: add disabled and read-only modes (#211) - - main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them. - - main: make it so that a frame with no window registered won't refocus every window on subsequent frames (~bump LastFrameActive of all windows). + - main: considering adding an Init() function? some constructs are awkward in the implementation because of the lack of them. +!- main: make it so that a frame with no window registered won't refocus every window on subsequent frames (~bump LastFrameActive of all windows). - main: IsItemHovered() make it 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: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) + - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now. - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) + - input text: flag to disable live update of the user buffer (also applies to float/int text input) + - input text: resize behavior - field could stretch when being edited? hover tooltip shows more text? + - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200) - input text multi-line: line numbers? status bar? (follow up on #200) + - input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position. - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: use mouse wheel to step up/down @@ -495,7 +500,7 @@ - statusbar: add a per-window status bar helper similar to what menubar does. - tabs (#261, #351) - separator: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y) - - color: the color helpers/typing is a mess and needs sorting out. +!- color: the color helpers/typing is a mess and needs sorting out. - color: add a better color picker (#346) - node/graph editor (#306) - pie menus patterns (#434) @@ -510,14 +515,11 @@ - slider & drag: int data passing through a float - drag float: up/down axis - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) - - text edit: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now. - - text edit: centered text for slider as input text so it matches typical positioning. - - text edit: flag to disable live update of the user buffer. - - text edit: field resize behavior - field could stretch when being edited? hover tooltip shows more text? - tree node / optimization: avoid formatting when clipped. - tree node: clarify spacing, perhaps provide API to query exact spacing. provide API to draw the primitive. same with Bullet(). - tree node: tree-node/header right-most side doesn't take account of horizontal scrolling. - tree node: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings + - tree node: try to apply scrolling at time of TreePop() if node was just opened and end of node is past scrolling limits? - tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer) - textwrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (git issue #249) - settings: write more decent code to allow saving/loading new fields @@ -527,6 +529,7 @@ - style: color-box not always square? - style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps to other settings? avoid implementing duplicate helpers such as SmallCheckbox(), etc. - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation). + - style/opt: PopStyleVar could be optimized by having GetStyleVar returns the type, using a table mapping stylevar enum to data type. - style: global scale setting. - text: simple markup language for color change? - font: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier. @@ -550,7 +553,8 @@ - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438) - style editor: color child window height expressed in multiple of line height. - remote: make a system like RemoteImGui first-class citizen/project (#75) - - drawlist: user probably can't call Clear() because we expect a texture to be pushed in the stack. +!- demo: custom render demo pushes a clipping rectangle past parent window bounds. expose ImGui::PushClipRect() from imgui_internal.h? + - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - examples: directx9/directx11: save/restore device state more thoroughly. - optimization: use another hash function than crc32, e.g. FNV1a - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? diff --git a/imgui.h b/imgui.h index 50b5f76a..d4deb352 100644 --- a/imgui.h +++ b/imgui.h @@ -986,7 +986,8 @@ struct ImGuiTextEditCallbackData bool HasSelection() const { return SelectionStart != SelectionEnd; } }; -// ImColor() is just a helper that implicity converts to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) +// ImColor() helper to implicity converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) +// Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. // None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. struct ImColor { From d4d51a78027fa9e44da46fc712d05216a8d0186a Mon Sep 17 00:00:00 2001 From: Nicolas Guillemot Date: Sat, 2 Apr 2016 19:08:27 -0700 Subject: [PATCH 063/400] capture and restore all state --- .../directx11_example/imgui_impl_dx11.cpp | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 8451fb8e..4ca65201 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -116,6 +116,46 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); } + // Capture all the state that will be modified to restore it afterwards + UINT oldNumScissorRects = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + D3D11_RECT oldScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + g_pd3dDeviceContext->RSGetScissorRects(&oldNumScissorRects, oldScissorRects); + ID3D11ShaderResourceView* pOldPSSRV0; + g_pd3dDeviceContext->PSGetShaderResources(0, 1, &pOldPSSRV0); + ID3D11RasterizerState* pOldRS; + g_pd3dDeviceContext->RSGetState(&pOldRS); + ID3D11BlendState* pOldBlendState; + FLOAT oldBlendFactor[4]; + UINT oldSampleMask; + g_pd3dDeviceContext->OMGetBlendState(&pOldBlendState, oldBlendFactor, &oldSampleMask); + ID3D11SamplerState* pOldPSSampler; + g_pd3dDeviceContext->PSGetSamplers(0, 1, &pOldPSSampler); + ID3D11PixelShader* pOldPS; + ID3D11ClassInstance* pOldPSInstances[256]; // max according to PSSetShader documentation + UINT oldNumPSInstances = 256; + g_pd3dDeviceContext->PSGetShader(&pOldPS, pOldPSInstances, &oldNumPSInstances); + ID3D11Buffer* pOldVSCBV; + g_pd3dDeviceContext->VSGetConstantBuffers(0, 1, &pOldVSCBV); + ID3D11VertexShader* pOldVS; + ID3D11ClassInstance* pOldVSInstances[256]; // max according to VSSetShader documentation + UINT oldNumVSInstances = 256; + g_pd3dDeviceContext->VSGetShader(&pOldVS, pOldVSInstances, &oldNumVSInstances); + D3D11_PRIMITIVE_TOPOLOGY oldPrimitiveTopology; + g_pd3dDeviceContext->IAGetPrimitiveTopology(&oldPrimitiveTopology); + ID3D11Buffer* pOldIndexBuffer; + DXGI_FORMAT oldIndexBufferFormat; + UINT oldIndexBufferOffset; + g_pd3dDeviceContext->IAGetIndexBuffer(&pOldIndexBuffer, &oldIndexBufferFormat, &oldIndexBufferOffset); + ID3D11Buffer* pOldVertexBuffer; + UINT oldVertexBufferStride; + UINT oldVertexBufferOffset; + g_pd3dDeviceContext->IAGetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); + ID3D11InputLayout* pOldInputLayout; + g_pd3dDeviceContext->IAGetInputLayout(&pOldInputLayout); + UINT oldNumViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + D3D11_VIEWPORT oldViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + g_pd3dDeviceContext->RSGetViewports(&oldNumViewports, oldViewports); + // Setup viewport { D3D11_VIEWPORT vp; @@ -172,9 +212,31 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) } // Restore modified state - g_pd3dDeviceContext->IASetInputLayout(NULL); - g_pd3dDeviceContext->PSSetShader(NULL, NULL, 0); - g_pd3dDeviceContext->VSSetShader(NULL, NULL, 0); + g_pd3dDeviceContext->RSSetScissorRects(oldNumScissorRects, oldScissorRects); + g_pd3dDeviceContext->PSSetShaderResources(0, 1, &pOldPSSRV0); + if (pOldPSSRV0) pOldPSSRV0->Release(); + g_pd3dDeviceContext->RSSetState(pOldRS); + if (pOldRS) pOldRS->Release(); + g_pd3dDeviceContext->OMSetBlendState(pOldBlendState, oldBlendFactor, oldSampleMask); + if (pOldBlendState) pOldBlendState->Release(); + g_pd3dDeviceContext->PSSetSamplers(0, 1, &pOldPSSampler); + if (pOldPSSampler) pOldPSSampler->Release(); + g_pd3dDeviceContext->PSSetShader(pOldPS, pOldPSInstances, oldNumPSInstances); + if (pOldPS) pOldPS->Release(); + for (UINT i = 0; i < oldNumPSInstances; i++) if (pOldPSInstances[i]) pOldPSInstances[i]->Release(); + g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &pOldVSCBV); + if (pOldVSCBV) pOldVSCBV->Release(); + g_pd3dDeviceContext->VSSetShader(pOldVS, pOldVSInstances, oldNumVSInstances); + if (pOldVS) pOldVS->Release(); + for (UINT i = 0; i < oldNumVSInstances; i++) if (pOldVSInstances[i]) pOldVSInstances[i]->Release(); + g_pd3dDeviceContext->IASetPrimitiveTopology(oldPrimitiveTopology); + g_pd3dDeviceContext->IASetIndexBuffer(pOldIndexBuffer, oldIndexBufferFormat, oldIndexBufferOffset); + if (pOldIndexBuffer) pOldIndexBuffer->Release(); + g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); + if (pOldVertexBuffer) pOldVertexBuffer->Release(); + g_pd3dDeviceContext->IASetInputLayout(pOldInputLayout); + if (pOldInputLayout) pOldInputLayout->Release(); + g_pd3dDeviceContext->RSSetViewports(oldNumViewports, oldViewports); } IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 2942240072c8b16387333ad313a80ab30e9ef6a4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 12:43:17 +0200 Subject: [PATCH 064/400] Examples: DX11: Cleanup state backup/restore code (#570) --- .../directx11_example/imgui_impl_dx11.cpp | 120 ++++++++---------- 1 file changed, 55 insertions(+), 65 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 4ca65201..bc6a0858 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -116,45 +116,45 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); } - // Capture all the state that will be modified to restore it afterwards - UINT oldNumScissorRects = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - D3D11_RECT oldScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; - g_pd3dDeviceContext->RSGetScissorRects(&oldNumScissorRects, oldScissorRects); - ID3D11ShaderResourceView* pOldPSSRV0; - g_pd3dDeviceContext->PSGetShaderResources(0, 1, &pOldPSSRV0); - ID3D11RasterizerState* pOldRS; - g_pd3dDeviceContext->RSGetState(&pOldRS); - ID3D11BlendState* pOldBlendState; - FLOAT oldBlendFactor[4]; - UINT oldSampleMask; - g_pd3dDeviceContext->OMGetBlendState(&pOldBlendState, oldBlendFactor, &oldSampleMask); - ID3D11SamplerState* pOldPSSampler; - g_pd3dDeviceContext->PSGetSamplers(0, 1, &pOldPSSampler); - ID3D11PixelShader* pOldPS; - ID3D11ClassInstance* pOldPSInstances[256]; // max according to PSSetShader documentation - UINT oldNumPSInstances = 256; - g_pd3dDeviceContext->PSGetShader(&pOldPS, pOldPSInstances, &oldNumPSInstances); - ID3D11Buffer* pOldVSCBV; - g_pd3dDeviceContext->VSGetConstantBuffers(0, 1, &pOldVSCBV); - ID3D11VertexShader* pOldVS; - ID3D11ClassInstance* pOldVSInstances[256]; // max according to VSSetShader documentation - UINT oldNumVSInstances = 256; - g_pd3dDeviceContext->VSGetShader(&pOldVS, pOldVSInstances, &oldNumVSInstances); - D3D11_PRIMITIVE_TOPOLOGY oldPrimitiveTopology; - g_pd3dDeviceContext->IAGetPrimitiveTopology(&oldPrimitiveTopology); - ID3D11Buffer* pOldIndexBuffer; - DXGI_FORMAT oldIndexBufferFormat; - UINT oldIndexBufferOffset; - g_pd3dDeviceContext->IAGetIndexBuffer(&pOldIndexBuffer, &oldIndexBufferFormat, &oldIndexBufferOffset); - ID3D11Buffer* pOldVertexBuffer; - UINT oldVertexBufferStride; - UINT oldVertexBufferOffset; - g_pd3dDeviceContext->IAGetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); - ID3D11InputLayout* pOldInputLayout; - g_pd3dDeviceContext->IAGetInputLayout(&pOldInputLayout); - UINT oldNumViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - D3D11_VIEWPORT oldViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; - g_pd3dDeviceContext->RSGetViewports(&oldNumViewports, oldViewports); + // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) + ID3D11DeviceContext* ctx = g_pd3dDeviceContext; + struct BACKUP_DX11_STATE + { + UINT ScissorRectsCount, ViewportsCount; + D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + ID3D11RasterizerState* RS; + ID3D11BlendState* BlendState; + FLOAT BlendFactor[4]; + UINT SampleMask; + ID3D11ShaderResourceView* PSShaderResource; + ID3D11SamplerState* PSSampler; + ID3D11PixelShader* PS; + ID3D11VertexShader* VS; + UINT PSInstancesCount, VSInstancesCount; + ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation + D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology; + ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; + UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; + DXGI_FORMAT IndexBufferFormat; + ID3D11InputLayout* InputLayout; + }; + BACKUP_DX11_STATE old; + old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); + ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); + ctx->RSGetState(&old.RS); + ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); + ctx->PSGetSamplers(0, 1, &old.PSSampler); + old.PSInstancesCount = old.VSInstancesCount = 256; + ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); + ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); + ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); + ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); + ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); + ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); + ctx->IAGetInputLayout(&old.InputLayout); // Setup viewport { @@ -211,32 +211,22 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) vtx_offset += cmd_list->VtxBuffer.size(); } - // Restore modified state - g_pd3dDeviceContext->RSSetScissorRects(oldNumScissorRects, oldScissorRects); - g_pd3dDeviceContext->PSSetShaderResources(0, 1, &pOldPSSRV0); - if (pOldPSSRV0) pOldPSSRV0->Release(); - g_pd3dDeviceContext->RSSetState(pOldRS); - if (pOldRS) pOldRS->Release(); - g_pd3dDeviceContext->OMSetBlendState(pOldBlendState, oldBlendFactor, oldSampleMask); - if (pOldBlendState) pOldBlendState->Release(); - g_pd3dDeviceContext->PSSetSamplers(0, 1, &pOldPSSampler); - if (pOldPSSampler) pOldPSSampler->Release(); - g_pd3dDeviceContext->PSSetShader(pOldPS, pOldPSInstances, oldNumPSInstances); - if (pOldPS) pOldPS->Release(); - for (UINT i = 0; i < oldNumPSInstances; i++) if (pOldPSInstances[i]) pOldPSInstances[i]->Release(); - g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &pOldVSCBV); - if (pOldVSCBV) pOldVSCBV->Release(); - g_pd3dDeviceContext->VSSetShader(pOldVS, pOldVSInstances, oldNumVSInstances); - if (pOldVS) pOldVS->Release(); - for (UINT i = 0; i < oldNumVSInstances; i++) if (pOldVSInstances[i]) pOldVSInstances[i]->Release(); - g_pd3dDeviceContext->IASetPrimitiveTopology(oldPrimitiveTopology); - g_pd3dDeviceContext->IASetIndexBuffer(pOldIndexBuffer, oldIndexBufferFormat, oldIndexBufferOffset); - if (pOldIndexBuffer) pOldIndexBuffer->Release(); - g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); - if (pOldVertexBuffer) pOldVertexBuffer->Release(); - g_pd3dDeviceContext->IASetInputLayout(pOldInputLayout); - if (pOldInputLayout) pOldInputLayout->Release(); - g_pd3dDeviceContext->RSSetViewports(oldNumViewports, oldViewports); + // Restore modified DX state + ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); + ctx->RSSetViewports(old.ViewportsCount, old.Viewports); + ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); + ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); + ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); + ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); + for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release(); + ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); + ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); + for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release(); + ctx->IASetPrimitiveTopology(old.PrimitiveTopology); + ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); + ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); + ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 90493f8add46738278d8b60ba9131d3673057c74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 12:48:38 +0200 Subject: [PATCH 065/400] Examples: DirectX11: Shallow massaging to make the code more consistent/readable (following #570) --- .../directx11_example/imgui_impl_dx11.cpp | 93 +++++++++---------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index bc6a0858..f02da129 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -46,6 +46,8 @@ struct VERTEX_CONSTANT_BUFFER // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { + ID3D11DeviceContext* ctx = g_pd3dDeviceContext; + // Create and grow vertex/index buffers if needed if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) { @@ -65,21 +67,21 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D11_BUFFER_DESC bufferDesc; - memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pIB) < 0) + D3D11_BUFFER_DESC buffer_desc; + memset(&buffer_desc, 0, sizeof(D3D11_BUFFER_DESC)); + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); + buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (g_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &g_pIB) < 0) return; } // Copy and convert all vertices into a single contiguous buffer D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; - if (g_pd3dDeviceContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) + if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) return; - if (g_pd3dDeviceContext->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) + if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; @@ -91,33 +93,31 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) vtx_dst += cmd_list->VtxBuffer.size(); idx_dst += cmd_list->IdxBuffer.size(); } - g_pd3dDeviceContext->Unmap(g_pVB, 0); - g_pd3dDeviceContext->Unmap(g_pIB, 0); + ctx->Unmap(g_pVB, 0); + ctx->Unmap(g_pIB, 0); // Setup orthographic projection matrix into our constant buffer { - D3D11_MAPPED_SUBRESOURCE mappedResource; - if (g_pd3dDeviceContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) + D3D11_MAPPED_SUBRESOURCE mapped_resource; + if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) return; - - VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData; - const float L = 0.0f; - const float R = ImGui::GetIO().DisplaySize.x; - const float B = ImGui::GetIO().DisplaySize.y; - const float T = 0.0f; - const float mvp[4][4] = + VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData; + float L = 0.0f; + float R = ImGui::GetIO().DisplaySize.x; + float B = ImGui::GetIO().DisplaySize.y; + float T = 0.0f; + float mvp[4][4] = { { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, { 0.0f, 0.0f, 0.5f, 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, }; - memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp)); - g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); + ctx->Unmap(g_pVertexConstantBuffer, 0); } // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) - ID3D11DeviceContext* ctx = g_pd3dDeviceContext; struct BACKUP_DX11_STATE { UINT ScissorRectsCount, ViewportsCount; @@ -157,34 +157,31 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->IAGetInputLayout(&old.InputLayout); // Setup viewport - { - D3D11_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D11_VIEWPORT)); - vp.Width = ImGui::GetIO().DisplaySize.x; - vp.Height = ImGui::GetIO().DisplaySize.y; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - g_pd3dDeviceContext->RSSetViewports(1, &vp); - } + D3D11_VIEWPORT vp; + memset(&vp, 0, sizeof(D3D11_VIEWPORT)); + vp.Width = ImGui::GetIO().DisplaySize.x; + vp.Height = ImGui::GetIO().DisplaySize.y; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = vp.TopLeftY = 0.0f; + ctx->RSSetViewports(1, &vp); // Bind shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; - g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout); - g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); - g_pd3dDeviceContext->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); - g_pd3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0); - g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); - g_pd3dDeviceContext->PSSetShader(g_pPixelShader, NULL, 0); - g_pd3dDeviceContext->PSSetSamplers(0, 1, &g_pFontSampler); + ctx->IASetInputLayout(g_pInputLayout); + ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); + ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->VSSetShader(g_pVertexShader, NULL, 0); + ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); + ctx->PSSetShader(g_pPixelShader, NULL, 0); + ctx->PSSetSamplers(0, 1, &g_pFontSampler); // Setup render state - const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; - g_pd3dDeviceContext->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff); - g_pd3dDeviceContext->RSSetState(g_pRasterizerState); + const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; + ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->RSSetState(g_pRasterizerState); // Render command lists int vtx_offset = 0; @@ -202,9 +199,9 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) else { const D3D11_RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; - g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId); - g_pd3dDeviceContext->RSSetScissorRects(1, &r); - g_pd3dDeviceContext->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); + ctx->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId); + ctx->RSSetScissorRects(1, &r); + ctx->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); } idx_offset += pcmd->ElemCount; } From 518f32ccfeab5d2c71e072c136ed305434aa9fea Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 12:59:56 +0200 Subject: [PATCH 066/400] Examples: DirectX10: Save/restore state + minor cleanups (#570) --- .../directx10_example/imgui_impl_dx10.cpp | 129 ++++++++++++------ 1 file changed, 86 insertions(+), 43 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 21f86f5d..3afe289a 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -46,6 +46,8 @@ struct VERTEX_CONSTANT_BUFFER // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) { + ID3D10Device* ctx = g_pd3dDevice; + // Create and grow vertex/index buffers if needed if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) { @@ -58,7 +60,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; desc.MiscFlags = 0; - if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0) + if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0) return; } @@ -66,13 +68,13 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D10_BUFFER_DESC bufferDesc; - memset(&bufferDesc, 0, sizeof(D3D10_BUFFER_DESC)); - bufferDesc.Usage = D3D10_USAGE_DYNAMIC; - bufferDesc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); - bufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pIB) < 0) + D3D10_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); + desc.BindFlags = D3D10_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0) return; } @@ -81,7 +83,6 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) ImDrawIdx* idx_dst = NULL; g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst); g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst); - for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; @@ -95,11 +96,10 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) // Setup orthographic projection matrix into our constant buffer { - void* mappedResource; - if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) + void* mapped_resource; + if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) return; - - VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource; + VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource; const float L = 0.0f; const float R = ImGui::GetIO().DisplaySize.x; const float B = ImGui::GetIO().DisplaySize.y; @@ -111,39 +111,72 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) { 0.0f, 0.0f, 0.5f, 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, }; - memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp)); + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); g_pVertexConstantBuffer->Unmap(); } - // Setup viewport + // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) + struct BACKUP_DX10_STATE { - D3D10_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D10_VIEWPORT)); - vp.Width = (UINT)ImGui::GetIO().DisplaySize.x; - vp.Height = (UINT)ImGui::GetIO().DisplaySize.y; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - g_pd3dDevice->RSSetViewports(1, &vp); - } + UINT ScissorRectsCount, ViewportsCount; + D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + ID3D10RasterizerState* RS; + ID3D10BlendState* BlendState; + FLOAT BlendFactor[4]; + UINT SampleMask; + ID3D10ShaderResourceView* PSShaderResource; + ID3D10SamplerState* PSSampler; + ID3D10PixelShader* PS; + ID3D10VertexShader* VS; + D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology; + ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; + UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; + DXGI_FORMAT IndexBufferFormat; + ID3D10InputLayout* InputLayout; + }; + BACKUP_DX10_STATE old; + old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); + ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); + ctx->RSGetState(&old.RS); + ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); + ctx->PSGetSamplers(0, 1, &old.PSSampler); + ctx->PSGetShader(&old.PS); + ctx->VSGetShader(&old.VS); + ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); + ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); + ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); + ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); + ctx->IAGetInputLayout(&old.InputLayout); + + // Setup viewport + D3D10_VIEWPORT vp; + memset(&vp, 0, sizeof(D3D10_VIEWPORT)); + vp.Width = (UINT)ImGui::GetIO().DisplaySize.x; + vp.Height = (UINT)ImGui::GetIO().DisplaySize.y; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = vp.TopLeftY = 0; + ctx->RSSetViewports(1, &vp); // Bind shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; - g_pd3dDevice->IASetInputLayout(g_pInputLayout); - g_pd3dDevice->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); - g_pd3dDevice->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); - g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - g_pd3dDevice->VSSetShader(g_pVertexShader); - g_pd3dDevice->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); - g_pd3dDevice->PSSetShader(g_pPixelShader); - g_pd3dDevice->PSSetSamplers(0, 1, &g_pFontSampler); + ctx->IASetInputLayout(g_pInputLayout); + ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); + ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); + ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->VSSetShader(g_pVertexShader); + ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); + ctx->PSSetShader(g_pPixelShader); + ctx->PSSetSamplers(0, 1, &g_pFontSampler); // Setup render state - const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; - g_pd3dDevice->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff); - g_pd3dDevice->RSSetState(g_pRasterizerState); + const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; + ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->RSSetState(g_pRasterizerState); // Render command lists int vtx_offset = 0; @@ -161,19 +194,29 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) else { const D3D10_RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; - g_pd3dDevice->PSSetShaderResources(0, 1, (ID3D10ShaderResourceView**)&pcmd->TextureId); - g_pd3dDevice->RSSetScissorRects(1, &r); - g_pd3dDevice->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); + ctx->PSSetShaderResources(0, 1, (ID3D10ShaderResourceView**)&pcmd->TextureId); + ctx->RSSetScissorRects(1, &r); + ctx->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); } idx_offset += pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.size(); } - // Restore modified state - g_pd3dDevice->IASetInputLayout(NULL); - g_pd3dDevice->PSSetShader(NULL); - g_pd3dDevice->VSSetShader(NULL); + // Restore modified DX state + ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); + ctx->RSSetViewports(old.ViewportsCount, old.Viewports); + ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); + ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); + ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); + ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release(); + ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release(); + ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); + ctx->IASetPrimitiveTopology(old.PrimitiveTopology); + ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); + ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); + ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } IMGUI_API LRESULT ImGui_ImplDX10_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 552246feed953887b1035fe4ed7d4c4290144068 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 13:02:04 +0200 Subject: [PATCH 067/400] Examples: DirectX10,DirectX11 : Minor renaming --- .../directx10_example/imgui_impl_dx10.cpp | 82 +++++++++--------- .../directx11_example/imgui_impl_dx11.cpp | 83 +++++++++---------- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 3afe289a..f0e57f72 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -277,33 +277,33 @@ static void ImGui_ImplDX10_CreateFontsTexture() // Create DX10 texture { - D3D10_TEXTURE2D_DESC texDesc; - ZeroMemory(&texDesc, sizeof(texDesc)); - texDesc.Width = width; - texDesc.Height = height; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - texDesc.SampleDesc.Count = 1; - texDesc.Usage = D3D10_USAGE_DEFAULT; - texDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE; - texDesc.CPUAccessFlags = 0; + D3D10_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.Usage = D3D10_USAGE_DEFAULT; + desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; ID3D10Texture2D *pTexture = NULL; D3D10_SUBRESOURCE_DATA subResource; subResource.pSysMem = pixels; - subResource.SysMemPitch = texDesc.Width * 4; + subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); + g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); // Create texture view - D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc; - ZeroMemory(&srvDesc, sizeof(srvDesc)); - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = texDesc.MipLevels; - srvDesc.Texture2D.MostDetailedMip = 0; - g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView); + D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; + ZeroMemory(&srv_desc, sizeof(srv_desc)); + srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = desc.MipLevels; + srv_desc.Texture2D.MostDetailedMip = 0; + g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView); pTexture->Release(); } @@ -312,17 +312,17 @@ static void ImGui_ImplDX10_CreateFontsTexture() // Create texture sampler { - D3D10_SAMPLER_DESC samplerDesc; - ZeroMemory(&samplerDesc, sizeof(samplerDesc)); - samplerDesc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP; - samplerDesc.MipLODBias = 0.f; - samplerDesc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; - samplerDesc.MinLOD = 0.f; - samplerDesc.MaxLOD = 0.f; - g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); + D3D10_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler); } // Cleanup (don't clear the input data if you want to append new fonts later) @@ -374,24 +374,24 @@ bool ImGui_ImplDX10_CreateDeviceObjects() return false; // Create the input layout - D3D10_INPUT_ELEMENT_DESC localLayout[] = { + D3D10_INPUT_ELEMENT_DESC local_layout[] = + { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; - - if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) + if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) return false; // Create the constant buffer { - D3D10_BUFFER_DESC cbDesc; - cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); - cbDesc.Usage = D3D10_USAGE_DYNAMIC; - cbDesc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - cbDesc.MiscFlags = 0; - g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer); + D3D10_BUFFER_DESC desc; + desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer); } } diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index f02da129..5f209bc0 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -67,13 +67,13 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D11_BUFFER_DESC buffer_desc; - memset(&buffer_desc, 0, sizeof(D3D11_BUFFER_DESC)); - buffer_desc.Usage = D3D11_USAGE_DYNAMIC; - buffer_desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); - buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; - buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - if (g_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &g_pIB) < 0) + D3D11_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0) return; } @@ -283,31 +283,31 @@ static void ImGui_ImplDX11_CreateFontsTexture() // Upload texture to graphics system { - D3D11_TEXTURE2D_DESC texDesc; - ZeroMemory(&texDesc, sizeof(texDesc)); - texDesc.Width = width; - texDesc.Height = height; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - texDesc.SampleDesc.Count = 1; - texDesc.Usage = D3D11_USAGE_DEFAULT; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - texDesc.CPUAccessFlags = 0; + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; ID3D11Texture2D *pTexture = NULL; D3D11_SUBRESOURCE_DATA subResource; subResource.pSysMem = pixels; - subResource.SysMemPitch = texDesc.Width * 4; + subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); + g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); // Create texture view D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; ZeroMemory(&srvDesc, sizeof(srvDesc)); srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = texDesc.MipLevels; + srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView); pTexture->Release(); @@ -318,17 +318,17 @@ static void ImGui_ImplDX11_CreateFontsTexture() // Create texture sampler { - D3D11_SAMPLER_DESC samplerDesc; - ZeroMemory(&samplerDesc, sizeof(samplerDesc)); - samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.MipLODBias = 0.f; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - samplerDesc.MinLOD = 0.f; - samplerDesc.MaxLOD = 0.f; - g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); + D3D11_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler); } } @@ -376,24 +376,23 @@ bool ImGui_ImplDX11_CreateDeviceObjects() return false; // Create the input layout - D3D11_INPUT_ELEMENT_DESC localLayout[] = { + D3D11_INPUT_ELEMENT_DESC local_layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; - - if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) + if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) return false; // Create the constant buffer { - D3D11_BUFFER_DESC cbDesc; - cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); - cbDesc.Usage = D3D11_USAGE_DYNAMIC; - cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - cbDesc.MiscFlags = 0; - g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer); + D3D11_BUFFER_DESC desc; + desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer); } } From f45fd1cef67482ca326a6be6ec8cb64d76867641 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 16:42:35 +0200 Subject: [PATCH 068/400] Comments --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 1a21e1d0..f170b166 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -504,6 +504,7 @@ - color: add a better color picker (#346) - node/graph editor (#306) - pie menus patterns (#434) + - drag'n drop, dragging helpers (carry dragging info, visualize drag source before clicking, drop target, etc.) (#143, #479) - plot: PlotLines() should use the polygon-stroke facilities (currently issues with averaging normals) - plot: make it easier for user to draw extra stuff into the graph (e.g: draw basis, highlight certain points, 2d plots, multiple plots) - plot: "smooth" automatic scale over time, user give an input 0.0(full user scale) 1.0(full derived from value) From 0e7b9b8284ad0cc52f31e4021334825c4220a079 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 17:32:53 +0200 Subject: [PATCH 069/400] Examples: Vulkan: Coding style tweaks. --- examples/README.txt | 6 +- examples/vulkan_example/build_win32.bat | 4 + .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 293 +++++++----------- .../vulkan_example/imgui_impl_glfw_vulkan.h | 9 +- examples/vulkan_example/main.cpp | 110 ++++--- 5 files changed, 188 insertions(+), 234 deletions(-) create mode 100644 examples/vulkan_example/build_win32.bat diff --git a/examples/README.txt b/examples/README.txt index f8e0c55e..0259ae64 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -79,4 +79,8 @@ allegro5_example/ marmalade_example/ Marmalade example using IwGx - + +vulkan_example/ + Vulkan example. + This is quite long and tedious, because: Vulkan. + diff --git a/examples/vulkan_example/build_win32.bat b/examples/vulkan_example/build_win32.bat new file mode 100644 index 00000000..e8b5a6c7 --- /dev/null +++ b/examples/vulkan_example/build_win32.bat @@ -0,0 +1,4 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +mkdir Debug +cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\bin32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib + diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 4774f173..33d8e997 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -59,7 +59,8 @@ static VkBuffer g_IndexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; -static unsigned char __glsl_shader_vert_spv[] = { +static unsigned char __glsl_shader_vert_spv[] = +{ 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x6c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, @@ -161,7 +162,8 @@ static unsigned char __glsl_shader_vert_spv[] = { }; static unsigned int __glsl_shader_vert_spv_len = 1172; -static unsigned char __glsl_shader_frag_spv[] = { +static unsigned char __glsl_shader_frag_spv[] = +{ 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x6c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -224,15 +226,15 @@ static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties { VkPhysicalDeviceMemoryProperties prop; vkGetPhysicalDeviceMemoryProperties(g_Gpu, &prop); - for(uint32_t i=0; i < prop.memoryTypeCount; ++i) - if((prop.memoryTypes[i].propertyFlags & properties) == properties && - type_bits & (1<TotalVtxCount * sizeof(ImDrawVert); - if(!g_VertexBuffer[g_FrameIndex] || - g_VertexBufferSize[g_FrameIndex] < vertex_size){ - if(g_VertexBuffer[g_FrameIndex]) + if (!g_VertexBuffer[g_FrameIndex] || g_VertexBufferSize[g_FrameIndex] < vertex_size) + { + if (g_VertexBuffer[g_FrameIndex]) vkDestroyBuffer(g_Device, g_VertexBuffer[g_FrameIndex], g_Allocator); - if(g_VertexBufferMemory[g_FrameIndex]) + if (g_VertexBufferMemory[g_FrameIndex]) vkFreeMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], g_Allocator); - size_t vertex_buffer_size = ((vertex_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + size_t vertex_buffer_size = ((vertex_size-1) / g_BufferMemoryAlignment+1) * g_BufferMemoryAlignment; VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = vertex_buffer_size; buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(g_Device, - &buffer_info, - g_Allocator, - &g_VertexBuffer[g_FrameIndex]); + err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_VertexBuffer[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_VertexBuffer[g_FrameIndex], &req); @@ -267,38 +266,29 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_VertexBufferMemory[g_FrameIndex]); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_VertexBufferMemory[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); - err = vkBindBufferMemory(g_Device, - g_VertexBuffer[g_FrameIndex], - g_VertexBufferMemory[g_FrameIndex], 0); + err = vkBindBufferMemory(g_Device, g_VertexBuffer[g_FrameIndex], g_VertexBufferMemory[g_FrameIndex], 0); ImGui_ImplGlfwVulkan_VkResult(err); g_VertexBufferSize[g_FrameIndex] = vertex_buffer_size; } + // Create the Index Buffer: size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - if(!g_IndexBuffer[g_FrameIndex] || - g_IndexBufferSize[g_FrameIndex] < index_size){ - if(g_IndexBuffer[g_FrameIndex]) + if (!g_IndexBuffer[g_FrameIndex] || g_IndexBufferSize[g_FrameIndex] < index_size) + { + if (g_IndexBuffer[g_FrameIndex]) vkDestroyBuffer(g_Device, g_IndexBuffer[g_FrameIndex], g_Allocator); - if(g_IndexBufferMemory[g_FrameIndex]) + if (g_IndexBufferMemory[g_FrameIndex]) vkFreeMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], g_Allocator); - size_t index_buffer_size = ((index_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + size_t index_buffer_size = ((index_size-1) / g_BufferMemoryAlignment+1) * g_BufferMemoryAlignment; VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = index_buffer_size; buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(g_Device, - &buffer_info, - g_Allocator, - &g_IndexBuffer[g_FrameIndex]); + err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_IndexBuffer[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_IndexBuffer[g_FrameIndex], &req); @@ -306,38 +296,27 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_IndexBufferMemory[g_FrameIndex]); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_IndexBufferMemory[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); - err = vkBindBufferMemory(g_Device, - g_IndexBuffer[g_FrameIndex], - g_IndexBufferMemory[g_FrameIndex], 0); + err = vkBindBufferMemory(g_Device, g_IndexBuffer[g_FrameIndex], g_IndexBufferMemory[g_FrameIndex], 0); ImGui_ImplGlfwVulkan_VkResult(err); g_IndexBufferSize[g_FrameIndex] = index_buffer_size; } + // Upload Vertex and index Data: { ImDrawVert* vtx_dst; ImDrawIdx* idx_dst; - err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], - 0, vertex_size, 0, - reinterpret_cast(&vtx_dst)); + err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], 0, vertex_size, 0, (void**)(&vtx_dst)); ImGui_ImplGlfwVulkan_VkResult(err); - err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], - 0, index_size, 0, - reinterpret_cast(&idx_dst)); + err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], 0, index_size, 0, (void**)(&idx_dst)); ImGui_ImplGlfwVulkan_VkResult(err); - for(int n = 0; n < draw_data->CmdListsCount; n++){ + for (int n = 0; n < draw_data->CmdListsCount; n++) + { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, &cmd_list->VtxBuffer[0], - cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); - memcpy(idx_dst, &cmd_list->IdxBuffer[0], - cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); + memcpy(vtx_dst, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); + memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); vtx_dst += cmd_list->VtxBuffer.size(); idx_dst += cmd_list->IdxBuffer.size(); } @@ -353,29 +332,22 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) vkUnmapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex]); vkUnmapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex]); } + // Bind pipeline and descriptor sets: { - vkCmdBindPipeline(g_CommandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - g_Pipeline); + vkCmdBindPipeline(g_CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline); VkDescriptorSet desc_set[1] = {g_DescriptorSet}; - vkCmdBindDescriptorSets(g_CommandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - g_PipelineLayout, - 0, 1, desc_set, - 0, NULL); + vkCmdBindDescriptorSets(g_CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL); } + // Bind Vertex And Index Buffer: { VkBuffer vertex_buffers[1] = {g_VertexBuffer[g_FrameIndex]}; VkDeviceSize vertex_offset[1] = {0}; - vkCmdBindVertexBuffers(g_CommandBuffer, - 0, 1, - vertex_buffers, vertex_offset); - vkCmdBindIndexBuffer(g_CommandBuffer, - g_IndexBuffer[g_FrameIndex], - 0, VK_INDEX_TYPE_UINT16); + vkCmdBindVertexBuffers(g_CommandBuffer, 0, 1, vertex_buffers, vertex_offset); + vkCmdBindIndexBuffer(g_CommandBuffer, g_IndexBuffer[g_FrameIndex], 0, VK_INDEX_TYPE_UINT16); } + // Setup viewport: { VkViewport viewport; @@ -387,6 +359,7 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) viewport.maxDepth = 1.0f; vkCmdSetViewport(g_CommandBuffer, 0, 1, &viewport); } + // Setup scale and translation: { float scale[2]; @@ -395,39 +368,32 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) float translate[2]; translate[0] = -1.0f; translate[1] = -1.0f; - vkCmdPushConstants(g_CommandBuffer, - g_PipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, - sizeof(float) * 0, - sizeof(float) * 2, - scale); - vkCmdPushConstants(g_CommandBuffer, - g_PipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, - sizeof(float) * 2, - sizeof(float) * 2, - translate); + vkCmdPushConstants(g_CommandBuffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); + vkCmdPushConstants(g_CommandBuffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); } + // Render the command lists: int vtx_offset = 0; int idx_offset = 0; - for(int n = 0; n < draw_data->CmdListsCount; n++){ + for (int n = 0; n < draw_data->CmdListsCount; n++) + { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for(int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++){ + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if(pcmd->UserCallback){ + if (pcmd->UserCallback) + { pcmd->UserCallback(cmd_list, pcmd); } - else{ + else + { VkRect2D scissor; scissor.offset.x = static_cast(pcmd->ClipRect.x); scissor.offset.y = static_cast(pcmd->ClipRect.y); scissor.extent.width = static_cast(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = static_cast(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); - vkCmdDrawIndexed(g_CommandBuffer, - pcmd->ElemCount, 1, - idx_offset, vtx_offset, 0); + vkCmdDrawIndexed(g_CommandBuffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); } idx_offset += pcmd->ElemCount; } @@ -468,6 +434,7 @@ void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow*, int key, int, int action, int io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; } void ImGui_ImplGlfwVulkan_CharCallback(GLFWwindow*, unsigned int c) @@ -487,6 +454,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) size_t upload_size = width*height*4*sizeof(char); VkResult err; + // Create the Image: { VkImageCreateInfo info = {}; @@ -500,32 +468,23 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) info.arrayLayers = 1; info.samples = VK_SAMPLE_COUNT_1_BIT; info.tiling = VK_IMAGE_TILING_OPTIMAL; - info.usage = - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - err = vkCreateImage(g_Device, - &info, - g_Allocator, - &g_FontImage); + err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetImageMemoryRequirements(g_Device, g_FontImage, &req); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_FontMemory); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory); ImGui_ImplGlfwVulkan_VkResult(err); err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0); ImGui_ImplGlfwVulkan_VkResult(err); } + // Create the Image View: { VkResult err; @@ -537,12 +496,10 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; info.subresourceRange.levelCount = 1; info.subresourceRange.layerCount = 1; - err = vkCreateImageView(g_Device, - &info, - g_Allocator, - &g_FontView); + err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView); ImGui_ImplGlfwVulkan_VkResult(err); } + // Update the Descriptor Set: { VkDescriptorImageInfo desc_image[1] = {}; @@ -555,10 +512,9 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) write_desc[0].descriptorCount = 1; write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write_desc[0].pImageInfo = desc_image; - vkUpdateDescriptorSets(g_Device, - 1, write_desc, - 0, NULL); + vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL); } + // Create the Upload Buffer: { VkBufferCreateInfo buffer_info = {}; @@ -566,10 +522,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) buffer_info.size = upload_size; buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(g_Device, - &buffer_info, - g_Allocator, - &g_UploadBuffer); + err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req); @@ -577,22 +530,17 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_UploadBufferMemory); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory); ImGui_ImplGlfwVulkan_VkResult(err); err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0); ImGui_ImplGlfwVulkan_VkResult(err); } + // Upload to Buffer: { - char *map; - err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, - reinterpret_cast(&map)); + char* map = NULL; + err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map)); ImGui_ImplGlfwVulkan_VkResult(err); memcpy(map, pixels, upload_size); VkMappedMemoryRange range[1] = {}; @@ -616,21 +564,15 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, NULL, 0, NULL, 1, copy_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, copy_barrier); + VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; - vkCmdCopyBufferToImage(command_buffer, - g_UploadBuffer, - g_FontImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ®ion); + vkCmdCopyBufferToImage(command_buffer, g_UploadBuffer, g_FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + VkImageMemoryBarrier use_barrier[1] = {}; use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -643,16 +585,11 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, NULL, 0, NULL, 1, use_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier); } - io.Fonts->TexID = (void *)(intptr_t)g_FontImage; - io.Fonts->ClearInputData(); - io.Fonts->ClearTexData(); + // Store our identifier + io.Fonts->TexID = (void *)(intptr_t)g_FontImage; return true; } @@ -660,7 +597,6 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() { VkResult err; - VkShaderModule vert_module; VkShaderModule frag_module; @@ -679,7 +615,9 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_FontSampler){ + + if (!g_FontSampler) + { VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = VK_FILTER_LINEAR; @@ -690,13 +628,12 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.minLod = -1000; info.maxLod = 1000; - err = vkCreateSampler(g_Device, - &info, - g_Allocator, - &g_FontSampler); + err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_DescriptorSetLayout){ + + if (!g_DescriptorSetLayout) + { VkSampler sampler[1] = {g_FontSampler}; VkDescriptorSetLayoutBinding binding[1] = {}; binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; @@ -707,12 +644,10 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; info.bindingCount = 1; info.pBindings = binding; - err = vkCreateDescriptorSetLayout(g_Device, - &info, - g_Allocator, - &g_DescriptorSetLayout); + err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout); ImGui_ImplGlfwVulkan_VkResult(err); } + // Create Descriptor Set: { VkDescriptorSetAllocateInfo alloc_info = {}; @@ -723,7 +658,9 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_PipelineLayout){ + + if (!g_PipelineLayout) + { VkPushConstantRange push_constants[2] = {}; push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].offset = sizeof(float) * 0; @@ -738,8 +675,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() layout_info.pSetLayouts = set_layout; layout_info.pushConstantRangeCount = 2; layout_info.pPushConstantRanges = push_constants; - err = vkCreatePipelineLayout(g_Device, &layout_info, - g_Allocator, &g_PipelineLayout); + err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout); ImGui_ImplGlfwVulkan_VkResult(err); } @@ -805,17 +741,14 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; - color_attachment[0].colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineColorBlendStateCreateInfo blend_info = {}; blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; blend_info.attachmentCount = 1; blend_info.pAttachments = color_attachment; - VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR}; + VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.dynamicStateCount = 2; dynamic_state.pDynamicStates = dynamic_states; @@ -834,11 +767,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.pDynamicState = &dynamic_state; info.layout = g_PipelineLayout; info.renderPass = g_RenderPass; - err = vkCreateGraphicsPipelines(g_Device, - g_PipelineCache, - 1, &info, - g_Allocator, - &g_Pipeline); + err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline); ImGui_ImplGlfwVulkan_VkResult(err); vkDestroyShaderModule(g_Device, vert_module, g_Allocator); @@ -849,43 +778,47 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects() { - if(g_UploadBuffer){ + if (g_UploadBuffer) + { vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator); g_UploadBuffer = VK_NULL_HANDLE; } - if(g_UploadBufferMemory){ + if (g_UploadBufferMemory) + { vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator); g_UploadBufferMemory = VK_NULL_HANDLE; } } + void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects() { ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); - for(int i=0; i -#include -#include +#include // printf, fprintf +#include // abort #define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_VULKAN #include @@ -47,9 +47,10 @@ static VkClearValue g_ClearValue = {}; static void check_vk_result(VkResult err) { - if(err == 0) return; + if (err == 0) return; printf("VkResult %d\n", err); - if(err < 0) abort(); + if (err < 0) + abort(); } static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) @@ -58,15 +59,17 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkSwapchainKHR old_swapchain = g_Swapchain; err = vkDeviceWaitIdle(g_Device); check_vk_result(err); + // Destroy old Framebuffer: - for(uint32_t i=0; i Date: Sun, 3 Apr 2016 17:41:59 +0200 Subject: [PATCH 070/400] Examples: Libs: Update glfw binaries to glfw master. --- examples/libs/glfw/include/GLFW/glfw3.h | 2034 ++++++++++++----- examples/libs/glfw/include/GLFW/glfw3native.h | 242 +- examples/libs/glfw/lib-vc2010-32/glfw3.lib | Bin 129546 -> 187376 bytes examples/libs/glfw/lib-vc2010-64/glfw3.lib | Bin 202450 -> 291120 bytes 4 files changed, 1624 insertions(+), 652 deletions(-) diff --git a/examples/libs/glfw/include/GLFW/glfw3.h b/examples/libs/glfw/include/GLFW/glfw3.h index 89414491..f8ca3d61 100644 --- a/examples/libs/glfw/include/GLFW/glfw3.h +++ b/examples/libs/glfw/include/GLFW/glfw3.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.1 - www.glfw.org + * GLFW 3.2 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -38,58 +38,60 @@ extern "C" { * Doxygen documentation *************************************************************************/ -/*! @defgroup context Context handling +/*! @file glfw3.h + * @brief The header of the GLFW 3 API. * - * This is the reference documentation for context related functions. For more - * information, see the @ref context. + * This is the header file of the GLFW 3 API. It defines all its types and + * declares all its functions. + * + * For more information about how to use this file, see @ref build_include. */ -/*! @defgroup init Initialization, version and errors +/*! @defgroup context Context reference + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. + */ +/*! @defgroup vulkan Vulkan reference + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. + */ +/*! @defgroup init Initialization, version and error reference * * This is the reference documentation for initialization and termination of - * the library, version management and error handling. For more information, - * see the @ref intro. + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. */ -/*! @defgroup input Input handling +/*! @defgroup input Input reference * * This is the reference documentation for input related functions and types. - * For more information, see the @ref input. + * For more task-oriented information, see the @ref input_guide. */ -/*! @defgroup monitor Monitor handling +/*! @defgroup monitor Monitor reference * * This is the reference documentation for monitor related functions and types. - * For more information, see the @ref monitor. + * For more task-oriented information, see the @ref monitor_guide. */ -/*! @defgroup window Window handling +/*! @defgroup window Window reference * * This is the reference documentation for window related functions and types, - * including creation, deletion and event polling. For more information, see - * the @ref window. + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. */ /************************************************************************* - * Global definitions + * Compiler- and platform-specific preprocessor work *************************************************************************/ -/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ - -/* Please report any problems that you find with your compiler, which may - * be solved in this section! There are several compilers that I have not - * been able to test this file with yet. - * - * First: If we are we on Windows, we want a single define for it (_WIN32) - * (Note: For Cygwin the compiler flag -mwin32 should be used, but to - * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ - * to the list of "valid Win32 identifiers", which removes the need for - * -mwin32) +/* If we are we on Windows, we want a single define for it. */ -#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) #define _WIN32 #endif /* _WIN32 */ -/* In order for extension support to be portable, we need to define an - * OpenGL function call method. We use the keyword APIENTRY, which is - * defined for Win32. (Note: Windows also needs this for ) +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ #ifndef APIENTRY #ifdef _WIN32 @@ -99,51 +101,30 @@ extern "C" { #endif #endif /* APIENTRY */ -/* The following three defines are here solely to make some Windows-based - * files happy. Theoretically we could include , but - * it has the major drawback of severely polluting our namespace. +/* Some Windows OpenGL headers need this. */ - -/* Under Windows, we need WINGDIAPI defined */ #if !defined(WINGDIAPI) && defined(_WIN32) - #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) - /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ - #define WINGDIAPI __declspec(dllimport) - #elif defined(__LCC__) - /* LCC-Win32 */ - #define WINGDIAPI __stdcall - #else - /* Others (e.g. MinGW, Cygwin) */ - #define WINGDIAPI extern - #endif + #define WINGDIAPI __declspec(dllimport) #define GLFW_WINGDIAPI_DEFINED #endif /* WINGDIAPI */ -/* Some files also need CALLBACK defined */ +/* Some Windows GLU headers need this. + */ #if !defined(CALLBACK) && defined(_WIN32) - #if defined(_MSC_VER) - /* Microsoft Visual C++ */ - #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) - #define CALLBACK __stdcall - #else - #define CALLBACK - #endif - #else - /* Other Windows compilers */ - #define CALLBACK __stdcall - #endif + #define CALLBACK __stdcall #define GLFW_CALLBACK_DEFINED #endif /* CALLBACK */ -/* Most GL/glu.h variants on Windows need wchar_t - * OpenGL/gl.h blocks the definition of ptrdiff_t by glext.h on OS X */ -#if !defined(GLFW_INCLUDE_NONE) - #include -#endif +/* Most Windows GLU headers need wchar_t. + * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include +#include /* Include the chosen client API headers. */ -#if defined(__APPLE_CC__) +#if defined(__APPLE__) #if defined(GLFW_INCLUDE_GLCOREARB) #include #if defined(GLFW_INCLUDE_GLEXT) @@ -174,13 +155,15 @@ extern "C" { #elif defined(GLFW_INCLUDE_ES3) #include #if defined(GLFW_INCLUDE_GLEXT) - #include + #include #endif #elif defined(GLFW_INCLUDE_ES31) #include #if defined(GLFW_INCLUDE_GLEXT) - #include + #include #endif + #elif defined(GLFW_INCLUDE_VULKAN) + #include #elif !defined(GLFW_INCLUDE_NONE) #include #if defined(GLFW_INCLUDE_GLEXT) @@ -208,11 +191,7 @@ extern "C" { #define GLFWAPI __declspec(dllexport) #elif defined(_WIN32) && defined(GLFW_DLL) /* We are calling GLFW as a Win32 DLL */ - #if defined(__LCC__) - #define GLFWAPI extern - #else - #define GLFWAPI __declspec(dllimport) - #endif + #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) @@ -221,8 +200,6 @@ extern "C" { #define GLFWAPI #endif -/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ - /************************************************************************* * GLFW API tokens @@ -242,7 +219,7 @@ extern "C" { * backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 1 +#define GLFW_VERSION_MINOR 2 /*! @brief The revision number of the GLFW library. * * This is incremented when a bug fix release is made that does not contain any @@ -252,6 +229,24 @@ extern "C" { #define GLFW_VERSION_REVISION 0 /*! @} */ +/*! @name Boolean values + * @{ */ +/*! @brief One. + * + * One. Seriously. You don't _need_ to use this symbol in your code. It's + * just semantic sugar for the number 1. You can use `1` or `true` or `_True` + * or `GL_TRUE` or whatever you want. + */ +#define GLFW_TRUE 1 +/*! @brief Zero. + * + * Zero. Seriously. You don't _need_ to use this symbol in your code. It's + * just just semantic sugar for the number 0. You can use `0` or `false` or + * `_False` or `GL_FALSE` or whatever you want. + */ +#define GLFW_FALSE 0 +/*! @} */ + /*! @name Key and button actions * @{ */ /*! @brief The key or mouse button was released. @@ -426,6 +421,7 @@ extern "C" { #define GLFW_KEY_RIGHT_ALT 346 #define GLFW_KEY_RIGHT_SUPER 347 #define GLFW_KEY_MENU 348 + #define GLFW_KEY_LAST GLFW_KEY_MENU /*! @} */ @@ -505,12 +501,11 @@ extern "C" { * @{ */ /*! @brief GLFW has not been initialized. * - * This occurs if a GLFW function was called that may not be called unless the + * This occurs if a GLFW function was called that must not be called unless the * library is [initialized](@ref intro_init). * - * @par Analysis - * Application programmer error. Initialize GLFW before calling any function - * that requires initialization. + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. */ #define GLFW_NOT_INITIALIZED 0x00010001 /*! @brief No context is current for this thread. @@ -519,9 +514,8 @@ extern "C" { * current OpenGL or OpenGL ES context but no context is current on the calling * thread. One such function is @ref glfwSwapInterval. * - * @par Analysis - * Application programmer error. Ensure a context is current before calling - * functions that require a current context. + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. */ #define GLFW_NO_CURRENT_CONTEXT 0x00010002 /*! @brief One of the arguments to the function was an invalid enum value. @@ -530,8 +524,7 @@ extern "C" { * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref * glfwGetWindowAttrib. * - * @par Analysis - * Application programmer error. Fix the offending call. + * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_ENUM 0x00010003 /*! @brief One of the arguments to the function was an invalid value. @@ -542,46 +535,41 @@ extern "C" { * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead * result in a @ref GLFW_VERSION_UNAVAILABLE error. * - * @par Analysis - * Application programmer error. Fix the offending call. + * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_VALUE 0x00010004 /*! @brief A memory allocation failed. * * A memory allocation failed. * - * @par Analysis - * A bug in GLFW or the underlying operating system. Report the bug to our - * [issue tracker](https://github.com/glfw/glfw/issues). + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_OUT_OF_MEMORY 0x00010005 -/*! @brief GLFW could not find support for the requested client API on the - * system. +/*! @brief GLFW could not find support for the requested API on the system. * - * GLFW could not find support for the requested client API on the system. + * GLFW could not find support for the requested API on the system. * - * @par Analysis - * The installed graphics driver does not support the requested client API, or - * does not support it via the chosen context creation backend. Below are - * a few examples. + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. * * @par * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only - * supports OpenGL ES via EGL, while Nvidia and Intel only supports it via + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary - * driver. + * driver. Older graphics drivers do not support Vulkan. */ #define GLFW_API_UNAVAILABLE 0x00010006 /*! @brief The requested OpenGL or OpenGL ES version is not available. * - * The requested OpenGL or OpenGL ES version (including any requested profile - * or context option) is not available on this machine. + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. * - * @par Analysis - * The machine does not support your requirements. If your application is - * sufficiently flexible, downgrade your requirements and try again. - * Otherwise, inform the user that their machine does not match your + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your * requirements. * * @par @@ -597,9 +585,9 @@ extern "C" { * A platform-specific error occurred that does not match any of the more * specific categories. * - * @par Analysis - * A bug in GLFW or the underlying operating system. Report the bug to our - * [issue tracker](https://github.com/glfw/glfw/issues). + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_PLATFORM_ERROR 0x00010008 /*! @brief The requested format is not supported or available. @@ -610,8 +598,7 @@ extern "C" { * If emitted when querying the clipboard, the contents of the clipboard could * not be converted to the requested format. * - * @par Analysis - * If emitted during window creation, one or more + * @analysis If emitted during window creation, one or more * [hard constraints](@ref window_hints_hard) did not match any of the * available pixel formats. If your application is sufficiently flexible, * downgrade your requirements and try again. Otherwise, inform the user that @@ -622,6 +609,14 @@ extern "C" { * the user, as appropriate. */ #define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @brief The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_NO_WINDOW_CONTEXT 0x0001000A /*! @} */ #define GLFW_FOCUSED 0x00020001 @@ -631,6 +626,7 @@ extern "C" { #define GLFW_DECORATED 0x00020005 #define GLFW_AUTO_ICONIFY 0x00020006 #define GLFW_FLOATING 0x00020007 +#define GLFW_MAXIMIZED 0x00020008 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -658,7 +654,9 @@ extern "C" { #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 #define GLFW_OPENGL_PROFILE 0x00022008 #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 +#define GLFW_CONTEXT_NO_ERROR 0x0002200A +#define GLFW_NO_API 0 #define GLFW_OPENGL_API 0x00030001 #define GLFW_OPENGL_ES_API 0x00030002 @@ -736,14 +734,37 @@ extern "C" { * Generic function pointer used for returning client API function pointers * without forcing a cast from a regular pointer. * + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in version 3.0. + * @ingroup context */ typedef void (*GLFWglproc)(void); +/*! @brief Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa glfwGetInstanceProcAddress + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +typedef void (*GLFWvkproc)(void); + /*! @brief Opaque monitor object. * * Opaque monitor object. * + * @see @ref monitor_object + * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef struct GLFWmonitor GLFWmonitor; @@ -752,6 +773,10 @@ typedef struct GLFWmonitor GLFWmonitor; * * Opaque window object. * + * @see @ref window_object + * + * @since Added in version 3.0. + * * @ingroup window */ typedef struct GLFWwindow GLFWwindow; @@ -760,6 +785,10 @@ typedef struct GLFWwindow GLFWwindow; * * Opaque cursor object. * + * @see @ref cursor_object + * + * @since Added in version 3.1. + * * @ingroup cursor */ typedef struct GLFWcursor GLFWcursor; @@ -771,8 +800,11 @@ typedef struct GLFWcursor GLFWcursor; * @param[in] error An [error code](@ref errors). * @param[in] description A UTF-8 encoded string describing the error. * + * @sa @ref error_handling * @sa glfwSetErrorCallback * + * @since Added in version 3.0. + * * @ingroup init */ typedef void (* GLFWerrorfun)(int,const char*); @@ -787,8 +819,11 @@ typedef void (* GLFWerrorfun)(int,const char*); * @param[in] ypos The new y-coordinate, in screen coordinates, of the * upper-left corner of the client area of the window. * + * @sa @ref window_pos * @sa glfwSetWindowPosCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); @@ -801,8 +836,12 @@ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); * @param[in] width The new width, in screen coordinates, of the window. * @param[in] height The new height, in screen coordinates, of the window. * + * @sa @ref window_size * @sa glfwSetWindowSizeCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); @@ -813,8 +852,12 @@ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); * * @param[in] window The window that the user attempted to close. * + * @sa @ref window_close * @sa glfwSetWindowCloseCallback * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowclosefun)(GLFWwindow*); @@ -825,8 +868,12 @@ typedef void (* GLFWwindowclosefun)(GLFWwindow*); * * @param[in] window The window whose content needs to be refreshed. * + * @sa @ref window_refresh * @sa glfwSetWindowRefreshCallback * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); @@ -836,11 +883,14 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); * This is the function signature for window focus callback functions. * * @param[in] window The window that gained or lost input focus. - * @param[in] focused `GL_TRUE` if the window was given input focus, or - * `GL_FALSE` if it lost it. + * @param[in] focused `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. * + * @sa @ref window_focus * @sa glfwSetWindowFocusCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); @@ -851,11 +901,14 @@ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); * functions. * * @param[in] window The window that was iconified or restored. - * @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE` - * if it was restored. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. * + * @sa @ref window_iconify * @sa glfwSetWindowIconifyCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); @@ -869,8 +922,11 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); * @param[in] width The new width, in pixels, of the framebuffer. * @param[in] height The new height, in pixels, of the framebuffer. * + * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); @@ -886,8 +942,12 @@ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_mouse_button * @sa glfwSetMouseButtonCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * * @ingroup input */ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); @@ -897,11 +957,16 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); * This is the function signature for cursor position callback functions. * * @param[in] window The window that received the event. - * @param[in] xpos The new x-coordinate, in screen coordinates, of the cursor. - * @param[in] ypos The new y-coordinate, in screen coordinates, of the cursor. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the client area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * client area. * + * @sa @ref cursor_pos * @sa glfwSetCursorPosCallback * + * @since Added in version 3.0. Replaces `GLFWmouseposfun`. + * * @ingroup input */ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); @@ -911,11 +976,14 @@ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); * This is the function signature for cursor enter/leave callback functions. * * @param[in] window The window that received the event. - * @param[in] entered `GL_TRUE` if the cursor entered the window's client - * area, or `GL_FALSE` if it left it. + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client + * area, or `GLFW_FALSE` if it left it. * + * @sa @ref cursor_enter * @sa glfwSetCursorEnterCallback * + * @since Added in version 3.0. + * * @ingroup input */ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); @@ -928,8 +996,11 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); * @param[in] xoffset The scroll offset along the x-axis. * @param[in] yoffset The scroll offset along the y-axis. * + * @sa @ref scrolling * @sa glfwSetScrollCallback * + * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. + * * @ingroup input */ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); @@ -945,8 +1016,12 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_key * @sa glfwSetKeyCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * * @ingroup input */ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); @@ -958,8 +1033,12 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); * @param[in] window The window that received the event. * @param[in] codepoint The Unicode code point of the character. * + * @sa @ref input_char * @sa glfwSetCharCallback * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter. + * * @ingroup input */ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); @@ -976,8 +1055,11 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_char * @sa glfwSetCharModsCallback * + * @since Added in version 3.1. + * * @ingroup input */ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); @@ -988,10 +1070,13 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); * * @param[in] window The window that received the event. * @param[in] count The number of dropped files. - * @param[in] names The UTF-8 encoded path names of the dropped files. + * @param[in] paths The UTF-8 encoded file and/or directory path names. * + * @sa @ref path_drop * @sa glfwSetDropCallback * + * @since Added in version 3.1. + * * @ingroup input */ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); @@ -1003,16 +1088,42 @@ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); * @param[in] monitor The monitor that was connected or disconnected. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. * + * @sa @ref monitor_event * @sa glfwSetMonitorCallback * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); +/*! @brief The function signature for joystick configuration callbacks. + * + * This is the function signature for joystick configuration callback + * functions. + * + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref joystick_event + * @sa glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int,int); + /*! @brief Video mode type. * * This describes a single video mode. * + * @sa @ref monitor_modes + * @sa glfwGetVideoMode glfwGetVideoModes + * + * @since Added in version 1.0. + * @glfw3 Added refresh rate member. + * * @ingroup monitor */ typedef struct GLFWvidmode @@ -1041,8 +1152,11 @@ typedef struct GLFWvidmode * * This describes the gamma ramp for a monitor. * + * @sa @ref monitor_gamma * @sa glfwGetGammaRamp glfwSetGammaRamp * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef struct GLFWgammaramp @@ -1062,6 +1176,11 @@ typedef struct GLFWgammaramp } GLFWgammaramp; /*! @brief Image data. + * + * @sa @ref cursor_custom + * + * @since Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. */ typedef struct GLFWimage { @@ -1092,29 +1211,24 @@ typedef struct GLFWimage * succeeds, you should call @ref glfwTerminate before the application exits. * * Additional calls to this function after successful initialization but before - * termination will return `GL_TRUE` immediately. + * termination will return `GLFW_TRUE` immediately. * - * @return `GL_TRUE` if successful, or `GL_FALSE` if an + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * - * @remarks __OS X:__ This function will change the current directory of the + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark @osx This function will change the current directory of the * application to the `Contents/Resources` subdirectory of the application's * bundle, if present. This can be disabled with a * [compile-time option](@ref compile_options_osx). * - * @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to - * `"C"` then the environment's locale will be applied to that category. This - * is done because character input will not function when `LC_CTYPE` is set to - * `"C"`. If another locale was set before this function was called, it will - * be left untouched. - * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init * @sa glfwTerminate * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup init */ @@ -1132,21 +1246,21 @@ GLFWAPI int glfwInit(void); * call this function, as it is called by @ref glfwInit before it returns * failure. * - * @remarks This function may be called before @ref glfwInit. + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * - * @warning No window's context may be current on another thread when this - * function is called. + * @remark This function may be called before @ref glfwInit. * - * @par Reentrancy - * This function may not be called from a callback. + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init * @sa glfwInit * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup init */ @@ -1158,22 +1272,22 @@ GLFWAPI void glfwTerminate(void); * library. It is intended for when you are using GLFW as a shared library and * want to ensure that you are using the minimum required version. * - * Any or all of the version arguments may be `NULL`. This function always - * succeeds. + * Any or all of the version arguments may be `NULL`. * * @param[out] major Where to store the major version number, or `NULL`. * @param[out] minor Where to store the minor version number, or `NULL`. * @param[out] rev Where to store the revision number, or `NULL`. * - * @remarks This function may be called before @ref glfwInit. + * @errors None. * - * @par Thread Safety - * This function may be called from any thread. + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. * * @sa @ref intro_version * @sa glfwGetVersionString * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup init */ @@ -1184,28 +1298,27 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); * This function returns the compile-time generated * [version string](@ref intro_version_string) of the GLFW library binary. It * describes the version, platform, compiler and any platform-specific - * compile-time options. + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. * * __Do not use the version string__ to parse the GLFW library version. The - * @ref glfwGetVersion function already provides the version of the running - * library binary. + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. * - * This function always succeeds. + * @return The ASCII encoded GLFW version string. * - * @return The GLFW version string. + * @errors None. * - * @remarks This function may be called before @ref glfwInit. + * @remark This function may be called before @ref glfwInit. * - * @par Pointer Lifetime - * The returned string is static and compile-time generated. + * @pointer_lifetime The returned string is static and compile-time generated. * - * @par Thread Safety - * This function may be called from any thread. + * @thread_safety This function may be called from any thread. * * @sa @ref intro_version * @sa glfwGetVersion * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup init */ @@ -1231,14 +1344,15 @@ GLFWAPI const char* glfwGetVersionString(void); * callback. * @return The previously set callback, or `NULL` if no callback was set. * - * @remarks This function may be called before @ref glfwInit. + * @errors None. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref error_handling * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup init */ @@ -1247,26 +1361,27 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); /*! @brief Returns the currently connected monitors. * * This function returns an array of handles for all currently connected - * monitors. + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `NULL`. * * @param[out] count Where to store the number of monitors in the returned * array. This is set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if an - * [error](@ref error_handling) occurred. + * @return An array of monitor handles, or `NULL` if no monitors were found or + * if an [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is guaranteed to be valid only until the monitor configuration - * changes or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_monitors * @sa @ref monitor_event * @sa glfwGetPrimaryMonitor * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1275,18 +1390,22 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); /*! @brief Returns the primary monitor. * * This function returns the primary monitor. This is usually the monitor - * where elements like the Windows task bar or the OS X menu bar is located. + * where elements like the task bar or global menu bar are located. * - * @return The primary monitor, or `NULL` if an [error](@ref error_handling) - * occurred. + * @return The primary monitor, or `NULL` if no monitors were found or if an + * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. * * @sa @ref monitor_monitors * @sa glfwGetMonitors * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1304,12 +1423,14 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1334,15 +1455,16 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * @param[out] heightMM Where to store the height, in millimetres, of the * monitor's display area, or `NULL`. * - * @remarks __Windows:__ The OS calculates the returned physical size from the + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 calculates the returned physical size from the * current resolution and system DPI instead of querying the monitor EDID data. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1358,17 +1480,17 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* * @return The UTF-8 encoded name of the monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified monitor is disconnected or the - * library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1385,15 +1507,13 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @bug __X11:__ This callback is not yet called on monitor configuration - * changes. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_event * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1412,21 +1532,21 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); * @return An array of video modes, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified monitor is disconnected, this - * function is called again for that monitor or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_modes * @sa glfwGetVideoMode * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Changed to return an array of modes for a specific monitor. + * @since Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. * * @ingroup monitor */ @@ -1442,18 +1562,19 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); * @return The current mode of the monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified monitor is disconnected or the - * library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_modes * @sa glfwGetVideoModes * - * @since Added in GLFW 3.0. Replaces `glfwGetDesktopMode`. + * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. * * @ingroup monitor */ @@ -1462,17 +1583,20 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); /*! @brief Generates a gamma ramp and sets it for the specified monitor. * * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. + * and then calls @ref glfwSetGammaRamp with it. The value must be a finite + * number greater than zero. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1486,18 +1610,19 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); * @return The current gamma ramp, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned structure and its arrays are allocated and freed by GLFW. You - * should not free them yourself. They are valid until the specified monitor - * is disconnected, this function is called again for that monitor or the - * library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1512,17 +1637,22 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * - * @note Gamma ramp sizes other than 256 are not supported by all hardware. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Pointer Lifetime - * The specified gamma ramp is copied before this function returns. + * @remark Gamma ramp sizes other than 256 are not supported by all platforms + * or graphics hardware. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark @win32 The gamma ramp size must be 256. + * + * @pointer_lifetime The specified gamma ramp is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1533,13 +1663,14 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); * This function resets all window hints to their * [default values](@ref window_hints_values). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa glfwWindowHint * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1552,20 +1683,26 @@ GLFWAPI void glfwDefaultWindowHints(void); * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is * terminated. * - * @param[in] target The [window hint](@ref window_hints) to set. - * @param[in] hint The new value of the window hint. + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. * - * @par Thread Safety - * This function may only be called from the main thread. + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa glfwDefaultWindowHints * - * @since Added in GLFW 3.0. Replaces `glfwOpenWindowHint`. + * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. * * @ingroup window */ -GLFWAPI void glfwWindowHint(int target, int hint); +GLFWAPI void glfwWindowHint(int hint, int value); /*! @brief Creates a window and its associated context. * @@ -1582,21 +1719,21 @@ GLFWAPI void glfwWindowHint(int target, int hint); * requested, as not all parameters and hints are * [hard constraints](@ref window_hints_hard). This includes the size of the * window, especially for full screen windows. To query the actual attributes - * of the created window, framebuffer and context, use queries like @ref - * glfwGetWindowAttrib and @ref glfwGetWindowSize. + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. * * To create a full screen window, you need to specify the monitor the window - * will cover. If no monitor is specified, windowed mode will be used. Unless - * you have a way for the user to choose a specific monitor, it is recommended - * that you pick the primary monitor. For more information on how to query - * connected monitors, see @ref monitor_monitors. + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. * * For full screen windows, the specified size becomes the resolution of the - * window's _desired video mode_. As long as a full screen window has input - * focus, the supported video mode most closely matching the desired video mode - * is set for the specified monitor. For more information about full screen - * windows, including the creation of so called _windowed full screen_ or - * _borderless full screen_ windows, see @ref window_windowed_full_screen. + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. * * By default, newly created windows use the placement recommended by the * window system. To create the window at a specific position, make it @@ -1604,8 +1741,8 @@ GLFWAPI void glfwWindowHint(int target, int hint); * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) * it. * - * If a full screen window has input focus, the screensaver is prohibited from - * starting. + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. * * Window systems put limits on window sizes. Very large or very small window * dimensions may be overridden by the window system on creation. Check the @@ -1619,50 +1756,67 @@ GLFWAPI void glfwWindowHint(int target, int hint); * @param[in] height The desired height, in screen coordinates, of the window. * This must be greater than zero. * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` to use + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. * @return The handle of the created window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @remarks __Windows:__ Window creation will fail if the Microsoft GDI - * software OpenGL implementation is the only one available. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. * - * @remarks __Windows:__ If the executable has an icon resource named - * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is - * present, the `IDI_WINLOGO` icon will be used instead. + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. * - * @remarks __Windows:__ The context to share resources with may not be current - * on any other thread. + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` + * it will be set as the icon for the window. If no such icon is present, the + * `IDI_WINLOGO` icon will be used instead. * - * @remarks __OS X:__ The GLFW window has no icon, as it is not a document + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @osx The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. * For more information on bundles, see the * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) * in the Mac Developer Library. * - * @remarks __OS X:__ The first time a window is created the menu bar is - * populated with common commands like Hide, Quit and About. The About entry - * opens a minimal about dialog with information from the application's bundle. - * The menu bar can be disabled with a + * @remark @osx The first time a window is created the menu bar is populated + * with common commands like Hide, Quit and About. The About entry opens + * a minimal about dialog with information from the application's bundle. The + * menu bar can be disabled with a * [compile-time option](@ref compile_options_osx). * - * @remarks __X11:__ There is no mechanism for setting the window icon yet. + * @remark @osx On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the `NSHighResolutionCapable` + * key is enabled in the application bundle's `Info.plist`. For more + * information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. * - * @remarks __X11:__ Some window managers will not respect the placement of + * @remark @x11 There is no mechanism for setting the window icon yet. + * + * @remark @x11 Some window managers will not respect the placement of * initially hidden windows. * - * @par Reentrancy - * This function may not be called from a callback. + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation * @sa glfwDestroyWindow * - * @since Added in GLFW 3.0. Replaces `glfwOpenWindow`. + * @since Added in version 3.0. Replaces `glfwOpenWindow`. * * @ingroup window */ @@ -1678,19 +1832,20 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G * * @param[in] window The window to destroy. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * * @note The context of the specified window must not be current on any other * thread when this function is called. * - * @par Reentrancy - * This function may not be called from a callback. + * @reentrancy This function must not be called from a callback. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation * @sa glfwCreateWindow * - * @since Added in GLFW 3.0. Replaces `glfwCloseWindow`. + * @since Added in version 3.0. Replaces `glfwCloseWindow`. * * @ingroup window */ @@ -1703,12 +1858,14 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); * @param[in] window The window to query. * @return The value of the close flag. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_close * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1723,12 +1880,14 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); * @param[in] window The window whose flag to change. * @param[in] value The new value. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_close * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1742,20 +1901,62 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); * @param[in] window The window whose title to change. * @param[in] title The UTF-8 encoded window title. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @osx The window title will not be updated until the next time you + * process events. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_title * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + /*! @brief Retrieves the position of the client area of the specified window. * * This function retrieves the position, in screen coordinates, of the @@ -1770,13 +1971,15 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * @param[out] ypos Where to store the y-coordinate of the upper-left corner of * the client area, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * @sa glfwSetWindowPos * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1798,16 +2001,16 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); * @param[in] xpos The x-coordinate of the upper-left corner of the client area. * @param[in] ypos The y-coordinate of the upper-left corner of the client area. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * @sa glfwGetWindowPos * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1828,48 +2031,131 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * @param[out] height Where to store the height, in screen coordinates, of the * client area, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * @sa glfwSetWindowSize * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); +/*! @brief Sets the size limits of the specified window. + * + * This function sets the size limits of the client area of the specified + * window. If the window is full screen, the size limits only take effect if + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] minwidth The minimum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] minheight The minimum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] maxheight The maximum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowAspectRatio + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @brief Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the client area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] numer The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * @param[in] denom The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowSizeLimits + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + /*! @brief Sets the size of the client area of the specified window. * * This function sets the size, in screen coordinates, of the client area of * the specified window. * - * For full screen windows, this function selects and switches to the resolution - * closest to the specified size, without affecting the window's context. As - * the context is unaffected, the bit depths of the framebuffer remain - * unchanged. + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. * * The window manager may put limits on what sizes are allowed. GLFW cannot * and should not override these limits. * * @param[in] window The window to resize. - * @param[in] width The desired width of the specified window. - * @param[in] height The desired height of the specified window. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * @sa glfwGetWindowSize + * @sa glfwSetWindowMonitor * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1890,13 +2176,15 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); * @param[out] height Where to store the height, in pixels, of the framebuffer, * or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1926,12 +2214,14 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height) * @param[out] bottom Where to store the size, in screen coordinates, of the * bottom edge of the window frame, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup window */ @@ -1948,16 +2238,17 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int * * @param[in] window The window to iconify. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify * @sa glfwRestoreWindow + * @sa glfwMaximizeWindow * - * @since Added in GLFW 2.1. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1966,27 +2257,51 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * * This function restores the specified window if it was previously iconified - * (minimized). If the window is already restored, this function does nothing. + * (minimized) or maximized. If the window is already restored, this function + * does nothing. * * If the specified window is a full screen window, the resolution chosen for * the window is restored on the selected monitor. * * @param[in] window The window to restore. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwIconifyWindow + * @sa glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwRestoreWindow(GLFWwindow* window); + +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * * @par Thread Safety * This function may only be called from the main thread. * * @sa @ref window_iconify * @sa glfwIconifyWindow + * @sa glfwRestoreWindow * - * @since Added in GLFW 2.1. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in GLFW 3.2. * * @ingroup window */ -GLFWAPI void glfwRestoreWindow(GLFWwindow* window); +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); /*! @brief Makes the specified window visible. * @@ -1996,13 +2311,15 @@ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); * * @param[in] window The window to make visible. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide * @sa glfwHideWindow * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2016,18 +2333,48 @@ GLFWAPI void glfwShowWindow(GLFWwindow* window); * * @param[in] window The window to hide. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide * @sa glfwShowWindow * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwHideWindow(GLFWwindow* window); +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable + * this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(GLFWwindow* window); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is @@ -2037,17 +2384,67 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * @return The monitor, or `NULL` if the window is in windowed mode or an error * occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor + * @sa glfwSetWindowMonitor * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc.. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa glfwGetWindowMonitor + * @sa glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns an attribute of the specified window. * * This function returns the value of an attribute of the specified window or @@ -2059,12 +2456,22 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); * @return The value of the attribute, or zero if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs * - * @since Added in GLFW 3.0. Replaces `glfwGetWindowParam` and + * @since Added in version 3.0. Replaces `glfwGetWindowParam` and * `glfwGetGLVersion`. * * @ingroup window @@ -2080,13 +2487,15 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * @param[in] window The window whose pointer to set. * @param[in] pointer The new value. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_userptr * @sa glfwGetWindowUserPointer * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2099,13 +2508,15 @@ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); * * @param[in] window The window whose pointer to return. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_userptr * @sa glfwSetWindowUserPointer * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2123,12 +2534,13 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2146,15 +2558,14 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindow * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -2177,18 +2588,17 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @remarks __OS X:__ Selecting Quit from the application menu will - * trigger the close callback for all windows. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark @osx Selecting Quit from the application menu will trigger the close + * callback for all windows. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_close * - * @since Added in GLFW 2.5. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -2210,15 +2620,14 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_refresh * - * @since Added in GLFW 2.5. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -2240,12 +2649,13 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_focus * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2262,12 +2672,13 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2284,12 +2695,13 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_fbsize * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2313,16 +2725,18 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window * * Event processing is not required for joystick input to work. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup window */ @@ -2356,21 +2770,69 @@ GLFWAPI void glfwPollEvents(void); * * Event processing is not required for joystick input to work. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa glfwPollEvents + * @sa glfwWaitEventsTimeout * - * @since Added in GLFW 2.5. + * @since Added in version 2.5. * * @ingroup window */ GLFWAPI void glfwWaitEvents(void); +/*! @brief Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwPollEvents + * @sa glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + /*! @brief Posts an empty event to the event queue. * * This function posts an empty event from the current thread to the event @@ -2380,13 +2842,15 @@ GLFWAPI void glfwWaitEvents(void); * of threads in applications that do not create windows, use your threading * library of choice. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * * @sa @ref events * @sa glfwWaitEvents * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup window */ @@ -2402,12 +2866,14 @@ GLFWAPI void glfwPostEmptyEvent(void); * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa glfwSetInputMode * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -2428,37 +2894,96 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * and unlimited cursor movement. This is useful for implementing for * example 3D camera controls. * - * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to - * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` * the next time it is called even if the key had been released before the * call. This is useful when you are only interested in whether keys have been * pressed but not when or in which order. * * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either - * `GL_TRUE` to enable sticky mouse buttons, or `GL_FALSE` to disable it. If - * sticky mouse buttons are enabled, a mouse button press will ensure that @ref - * glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even if - * the mouse button had been released before the call. This is useful when you - * are only interested in whether mouse buttons have been pressed but not when - * or in which order. + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. * * @param[in] window The window whose input mode to set. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * @param[in] value The new value of the specified input mode. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa glfwGetInputMode * - * @since Added in GLFW 3.0. Replaces `glfwEnable` and `glfwDisable`. + * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. * * @ingroup input */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); +/*! @brief Returns the localized name of the specified printable key. + * + * This function returns the localized name of the specified printable key. + * This is intended for displaying key bindings to the user. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise + * the scancode is ignored. If a non-printable key or (if the key is + * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is + * specified, this function returns `NULL`. + * + * This behavior allows you to pass in the arguments passed to the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. + * @param[in] scancode The scancode of the key to query. + * @return The localized name of the key, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetKeyName, or until the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetKeyName(int key, int scancode); + /*! @brief Returns the last reported state of a keyboard key for the specified * window. * @@ -2478,20 +3003,22 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * The [modifier key bit masks](@ref mods) are not key tokens and cannot be * used with this function. * + * __Do not use this function__ to implement [text input](@ref input_char). + * * @param[in] window The desired window. * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is * not a valid key for this function. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup input */ @@ -2512,15 +3039,15 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); * @param[in] button The desired [mouse button](@ref buttons). * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_mouse_button * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup input */ @@ -2550,13 +3077,15 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); * @param[out] ypos Where to store the cursor y-coordinate, relative to the to * top edge of the client area, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * @sa glfwSetCursorPos * - * @since Added in GLFW 3.0. Replaces `glfwGetMousePos`. + * @since Added in version 3.0. Replaces `glfwGetMousePos`. * * @ingroup input */ @@ -2585,17 +3114,19 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * @param[in] ypos The desired y-coordinate, relative to the top edge of the * client area. * - * @remarks __X11:__ Due to the asynchronous nature of a modern X desktop, it - * may take a moment for the window focus event to arrive. This means you will - * not be able to set the cursor position directly after window creation. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * the window focus event to arrive. This means you may not be able to set the + * cursor position directly after window creation. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * @sa glfwGetCursorPos * - * @since Added in GLFW 3.0. Replaces `glfwSetMousePos`. + * @since Added in version 3.0. Replaces `glfwSetMousePos`. * * @ingroup input */ @@ -2607,9 +3138,9 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. * Any remaining cursors are destroyed by @ref glfwTerminate. * - * The pixels are 32-bit little-endian RGBA, i.e. eight bits per channel. They - * are arranged canonically as packed sequential rows, starting from the - * top-left corner. + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel. They are arranged canonically as packed sequential rows, + * starting from the top-left corner. * * The cursor hotspot is specified in pixels, relative to the upper-left corner * of the cursor image. Like all other coordinate systems in GLFW, the X-axis @@ -2618,24 +3149,24 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @param[in] image The desired cursor image. * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. - * * @return The handle of the created cursor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The specified image data is copied before this function returns. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Reentrancy - * This function may not be called from a callback. + * @pointer_lifetime The specified image data is copied before this function + * returns. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa glfwDestroyCursor * @sa glfwCreateStandardCursor * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2647,20 +3178,20 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) * a window with @ref glfwSetCursor. * * @param[in] shape One of the [standard shapes](@ref shapes). - * * @return A new cursor ready to use or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa glfwCreateCursor * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2674,16 +3205,17 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); * * @param[in] cursor The cursor object to destroy. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa glfwCreateCursor * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2703,12 +3235,14 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); * @param[in] cursor The cursor to set, or `NULL` to switch back to the default * arrow cursor. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2744,15 +3278,14 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -2783,15 +3316,14 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 2.4. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 2.4. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -2818,12 +3350,13 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * error occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2846,15 +3379,14 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_mouse_button * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -2873,12 +3405,13 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmo * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * - * @since Added in GLFW 3.0. Replaces `glfwSetMousePosCallback`. + * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. * * @ingroup input */ @@ -2896,12 +3429,13 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursor * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_enter * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -2922,12 +3456,13 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref scrolling * - * @since Added in GLFW 3.0. Replaces `glfwSetMouseWheelCallback`. + * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. * * @ingroup input */ @@ -2949,12 +3484,13 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref path_drop * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2965,14 +3501,16 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); * This function returns whether the specified joystick is present. * * @param[in] joy The [joystick](@ref joysticks) to query. - * @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise. + * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick * - * @since Added in GLFW 3.0. Replaces `glfwGetJoystickParam`. + * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. * * @ingroup input */ @@ -2983,22 +3521,28 @@ GLFWAPI int glfwJoystickPresent(int joy); * This function returns the values of all axes of the specified joystick. * Each element in the array is a value between -1.0 and 1.0. * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * * @param[in] joy The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of axis values in the returned * array. This is set to zero if an error occurred. * @return An array of axis values, or `NULL` if the joystick is not present. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified joystick is disconnected, this - * function is called again for that joystick or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_axis * - * @since Added in GLFW 3.0. Replaces `glfwGetJoystickPos`. + * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. * * @ingroup input */ @@ -3009,25 +3553,29 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); * This function returns the state of all buttons of the specified joystick. * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * * @param[in] joy The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of button states in the returned * array. This is set to zero if an error occurred. * @return An array of button states, or `NULL` if the joystick is not present. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified joystick is disconnected, this - * function is called again for that joystick or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_button * - * @since Added in GLFW 2.2. - * - * @par - * __GLFW 3:__ Changed to return a dynamic array. + * @since Added in version 2.2. + * @glfw3 Changed to return a dynamic array. * * @ingroup input */ @@ -3039,26 +3587,55 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); * The returned string is allocated and freed by GLFW. You should not free it * yourself. * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * * @param[in] joy The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick * is not present. * - * @par Pointer Lifetime - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified joystick is disconnected, this - * function is called again for that joystick or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_name * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ GLFWAPI const char* glfwGetJoystickName(int joy); +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); + /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded @@ -3067,16 +3644,18 @@ GLFWAPI const char* glfwGetJoystickName(int joy); * @param[in] window The window that will own the clipboard contents. * @param[in] string A UTF-8 encoded string. * - * @par Pointer Lifetime - * The specified string is copied before this function returns. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa glfwGetClipboardString * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -3085,25 +3664,28 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); /*! @brief Returns the contents of the clipboard as a string. * * This function returns the contents of the system clipboard, if it contains - * or is convertible to a UTF-8 encoded string. + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `NULL` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. * * @param[in] window The window that will request the clipboard contents. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the next call to @ref + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library * is terminated. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa glfwSetClipboardString * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -3122,12 +3704,14 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * @return The current value, in seconds, or zero if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Reading of the + * internal timer offset is not atomic. * * @sa @ref time * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup input */ @@ -3136,21 +3720,71 @@ GLFWAPI double glfwGetTime(void); /*! @brief Sets the GLFW timer. * * This function sets the value of the GLFW timer. It then continues to count - * up from that value. + * up from that value. The value must be a positive finite number less than + * or equal to 18446744073.0, which is approximately 584.5 years. * * @param[in] time The new value, in seconds. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of the timer is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @thread_safety This function may be called from any thread. Writing of the + * internal timer offset is not atomic. * * @sa @ref time * - * @since Added in GLFW 2.2. + * @since Added in version 2.2. * * @ingroup input */ GLFWAPI void glfwSetTime(double time); +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerFrequency(void); + /*! @brief Makes the context of the specified window current for the calling * thread. * @@ -3164,16 +3798,22 @@ GLFWAPI void glfwSetTime(double time); * whether a context performs this flush by setting the * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_current * @sa glfwGetCurrentContext * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup context */ @@ -3187,13 +3827,14 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); * @return The window whose context is current, or `NULL` if no window's * context is current. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_current * @sa glfwMakeContextCurrent * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup context */ @@ -3201,22 +3842,33 @@ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); /*! @brief Swaps the front and back buffers of the specified window. * - * This function swaps the front and back buffers of the specified window. If - * the swap interval is greater than zero, the GPU driver waits the specified - * number of screen updates before swapping the buffers. + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. * * @param[in] window The window whose buffers to swap. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. + * + * @thread_safety This function may be called from any thread. * * @sa @ref buffer_swap * @sa glfwSwapInterval * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -3224,11 +3876,11 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * - * This function sets the swap interval for the current context, i.e. the - * number of screen updates to wait from the time @ref glfwSwapBuffers was - * called before swapping the buffers and returning. This is sometimes called - * _vertical synchronization_, _vertical retrace synchronization_ or just - * _vsync_. + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. * * Contexts that support either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, @@ -3240,25 +3892,30 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * - * @note This function is not called during window creation, leaving the swap - * interval set to whatever is the default on that platform. This is done + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done * because some swap interval extensions used by GLFW do not allow the swap * interval to be reset to zero once it has been set to a non-zero value. * - * @note Some GPU drivers do not honor the requested swap interval, either - * because of user settings that override the request or due to bugs in the - * driver. + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. * - * @par Thread Safety - * This function may be called from any thread. + * @thread_safety This function may be called from any thread. * * @sa @ref buffer_swap * @sa glfwSwapBuffers * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup context */ @@ -3268,8 +3925,8 @@ GLFWAPI void glfwSwapInterval(int interval); * * This function returns whether the specified * [API extension](@ref context_glext) is supported by the current OpenGL or - * OpenGL ES context. It searches both for OpenGL and OpenGL ES extension and - * platform-specific context creation API extensions. + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. @@ -3279,16 +3936,24 @@ GLFWAPI void glfwSwapInterval(int interval); * frequently. The extension strings will not change during the lifetime of * a context, so there is no danger in doing this. * - * @param[in] extension The ASCII encoded name of the extension. - * @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise. + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. * - * @par Thread Safety - * This function may be called from any thread. + * @param[in] extension The ASCII encoded name of the extension. + * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_glext * @sa glfwGetProcAddress * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup context */ @@ -3297,36 +3962,243 @@ GLFWAPI int glfwExtensionSupported(const char* extension); /*! @brief Returns the address of the specified function for the current * context. * - * This function returns the address of the specified - * [client API or extension function](@ref context_glext), if it is supported + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported * by the current context. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * - * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if the function is - * unavailable or an [error](@ref error_handling) occurred. + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. * - * @note The addresses of a given function is not guaranteed to be the same + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark The address of a given function is not guaranteed to be the same * between contexts. * - * @par Pointer Lifetime - * The returned function pointer is valid until the context is destroyed or the - * library is terminated. + * @remark This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. * - * @par Thread Safety - * This function may be called from any thread. + * @pointer_lifetime The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_glext * @sa glfwExtensionSupported * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup context */ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); +/*! @brief Returns whether the Vulkan loader has been found. + * + * This function returns whether the Vulkan loader has been found. This check + * is performed by @ref glfwInit. + * + * The availability of a Vulkan loader does not by itself guarantee that window + * surface creation or even device creation is possible. Call @ref + * glfwGetRequiredInstanceExtensions to check whether the extensions necessary + * for Vulkan surface creation are available and @ref + * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of + * a physical device supports image presentation. + * + * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwVulkanSupported(void); + +/*! @brief Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contains `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `NULL`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * @param[out] count Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * @return An array of ASCII encoded extension names, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remarks Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa glfwCreateWindowSurface + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); + +#if defined(VK_VERSION_1_0) + +/*! @brief Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `NULL` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve + * functions related to instance creation. + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @pointer_lifetime The returned function pointer is valid until the library + * is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); + +/*! @brief Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * @param[in] instance The instance that the physical device belongs to. + * @param[in] device The physical device that the queue family belongs to. + * @param[in] queuefamily The index of the queue family to query. + * @return `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @brief Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader was not found at initialization, this function returns + * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE + * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was + * found. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * @param[in] instance The Vulkan instance to create the surface in. + * @param[in] window The window to create the surface for. + * @param[in] allocator The allocator to use, or `NULL` to use the default + * allocator. + * @param[out] surface Where to store the handle of the surface. This is set + * to `VK_NULL_HANDLE` if an error occurred. + * @return `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remarks If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa glfwGetRequiredInstanceExtensions + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +#endif /*VK_VERSION_1_0*/ + /************************************************************************* * Global definition cleanup diff --git a/examples/libs/glfw/include/GLFW/glfw3native.h b/examples/libs/glfw/include/GLFW/glfw3native.h index b3ce7482..9fa955e9 100644 --- a/examples/libs/glfw/include/GLFW/glfw3native.h +++ b/examples/libs/glfw/include/GLFW/glfw3native.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.1 - www.glfw.org + * GLFW 3.2 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -38,20 +38,30 @@ extern "C" { * Doxygen documentation *************************************************************************/ +/*! @file glfw3native.h + * @brief The header of the native access functions. + * + * This is the header file of the native access functions. See @ref native for + * more information. + */ /*! @defgroup native Native access * * **By using the native access functions you assert that you know what you're * doing and how to fix problems caused by using them. If you don't, you * shouldn't be using them.** * - * Before the inclusion of @ref glfw3native.h, you must define exactly one - * window system API macro and exactly one context creation API macro. Failure - * to do this will cause a compile-time error. + * Before the inclusion of @ref glfw3native.h, you may define exactly one + * window system API macro and zero or more context creation API macros. + * + * The chosen backends must match those the library was compiled for. Failure + * to do this will cause a link-time error. * * The available window API macros are: * * `GLFW_EXPOSE_NATIVE_WIN32` * * `GLFW_EXPOSE_NATIVE_COCOA` * * `GLFW_EXPOSE_NATIVE_X11` + * * `GLFW_EXPOSE_NATIVE_WAYLAND` + * * `GLFW_EXPOSE_NATIVE_MIR` * * The available context API macros are: * * `GLFW_EXPOSE_NATIVE_WGL` @@ -86,20 +96,23 @@ extern "C" { #elif defined(GLFW_EXPOSE_NATIVE_X11) #include #include -#else - #error "No window API selected" +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + #include +#elif defined(GLFW_EXPOSE_NATIVE_MIR) + #include #endif #if defined(GLFW_EXPOSE_NATIVE_WGL) /* WGL is declared by windows.h */ -#elif defined(GLFW_EXPOSE_NATIVE_NSGL) +#endif +#if defined(GLFW_EXPOSE_NATIVE_NSGL) /* NSGL is declared by Cocoa.h */ -#elif defined(GLFW_EXPOSE_NATIVE_GLX) +#endif +#if defined(GLFW_EXPOSE_NATIVE_GLX) #include -#elif defined(GLFW_EXPOSE_NATIVE_EGL) +#endif +#if defined(GLFW_EXPOSE_NATIVE_EGL) #include -#else - #error "No context API selected" #endif @@ -114,11 +127,10 @@ extern "C" { * of the specified monitor, or `NULL` if an [error](@ref error_handling) * occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -130,11 +142,10 @@ GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -145,11 +156,10 @@ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); * @return The `HWND` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -162,11 +172,10 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); * @return The `HGLRC` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -179,11 +188,10 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); * @return The `CGDirectDisplayID` of the specified monitor, or * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -194,11 +202,10 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); * @return The `NSWindow` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -211,11 +218,10 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); * @return The `NSOpenGLContext` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -228,11 +234,10 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); * @return The `Display` used by GLFW, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -243,11 +248,10 @@ GLFWAPI Display* glfwGetX11Display(void); * @return The `RRCrtc` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -258,11 +262,10 @@ GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); * @return The `RROutput` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -273,11 +276,10 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); * @return The `Window` of the specified window, or `None` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -290,15 +292,116 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); * @return The `GLXContext` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); + +/*! @brief Returns the `GLXWindow` of the specified window. + * + * @return The `GLXWindow` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) +/*! @brief Returns the `struct wl_display*` used by GLFW. + * + * @return The `struct wl_display*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); + +/*! @brief Returns the `struct wl_output*` of the specified monitor. + * + * @return The `struct wl_output*` of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the main `struct wl_surface*` of the specified window. + * + * @return The main `struct wl_surface*` of the specified window, or `NULL` if + * an [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_MIR) +/*! @brief Returns the `MirConnection*` used by GLFW. + * + * @return The `MirConnection*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirConnection* glfwGetMirDisplay(void); + +/*! @brief Returns the Mir output ID of the specified monitor. + * + * @return The Mir output ID of the specified monitor, or zero if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `MirSurface*` of the specified window. + * + * @return The `MirSurface*` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_EGL) @@ -307,11 +410,10 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -322,11 +424,10 @@ GLFWAPI EGLDisplay glfwGetEGLDisplay(void); * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -337,11 +438,10 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ diff --git a/examples/libs/glfw/lib-vc2010-32/glfw3.lib b/examples/libs/glfw/lib-vc2010-32/glfw3.lib index 014458efed8cff308e876c22c2e4832c705079eb..348abecfa98d6cfad9db67127eab8d5c72473539 100644 GIT binary patch literal 187376 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 z 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 L?xao99RL3TeG$IW diff --git a/examples/libs/glfw/lib-vc2010-64/glfw3.lib b/examples/libs/glfw/lib-vc2010-64/glfw3.lib index 8cdda39987fe55d400fa1def0738b4bdc8672d51..768f3083660f35ca37ce0d02a2541e92eb5cdade 100644 GIT binary patch literal 291120 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 It5l%>4{5MQ*Z=?k literal 202450 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 Date: Sun, 3 Apr 2016 23:28:05 +0200 Subject: [PATCH 071/400] Renamed ImGuiWindowFlags_Force**Scrollbar to ImGuiWindowFlags_Always**Scrollbar (#476) --- imgui.cpp | 4 ++-- imgui.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f170b166..4e4909df 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3980,8 +3980,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Scrollbars - window->ScrollbarY = (flags & ImGuiWindowFlags_ForceVerticalScrollbar) || ((window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar)); - window->ScrollbarX = (flags & ImGuiWindowFlags_ForceHorizontalScrollbar) || ((window->SizeContents.x > window->Size.x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f) - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > window->Size.x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f) - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f; diff --git a/imgui.h b/imgui.h index d4deb352..39746e58 100644 --- a/imgui.h +++ b/imgui.h @@ -466,11 +466,11 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file ImGuiWindowFlags_NoInputs = 1 << 9, // Disable catching mouse or keyboard inputs ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar - ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You need to use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programatically giving it focus) - ImGuiWindowFlags_ForceVerticalScrollbar = 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) - ImGuiWindowFlags_ForceHorizontalScrollbar=1 << 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) // [Internal] ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() From 07df3cfb3e4ad37523f834f9b77a58a56ae1746c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Apr 2016 00:29:57 +0200 Subject: [PATCH 072/400] Added ImGuiWindowFlags_AlwaysUseWindowPadding flag to ensure non-border child window uses window padding (#462) --- imgui.cpp | 2 +- imgui.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4e4909df..476ddf90 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3766,7 +3766,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Lock window padding so that altering the ShowBorders flag for children doesn't have side-effects. - window->WindowPadding = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : style.WindowPadding; + window->WindowPadding = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : style.WindowPadding; // Calculate auto-fit size ImVec2 size_auto_fit; diff --git a/imgui.h b/imgui.h index 39746e58..3d2e0277 100644 --- a/imgui.h +++ b/imgui.h @@ -471,6 +471,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programatically giving it focus) ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) // [Internal] ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() From 947171dcefe691286f53fafa36674ca6ce935327 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Apr 2016 00:30:50 +0200 Subject: [PATCH 073/400] Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(): outer frame not honoring bordering (following #462) --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 476ddf90..4a32088d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -693,7 +693,7 @@ ImGuiStyle::ImGuiStyle() WindowMinSize = ImVec2(32,32); // Minimum window size WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows WindowTitleAlign = ImGuiAlign_Left; // Alignment for title bar text - ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows + ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines @@ -3442,13 +3442,14 @@ bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags ext const ImGuiStyle& style = g.Style; ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, style.Colors[ImGuiCol_FrameBg]); ImGui::PushStyleVar(ImGuiStyleVar_ChildWindowRounding, style.FrameRounding); - return ImGui::BeginChild(id, size, false, ImGuiWindowFlags_NoMove | extra_flags); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + return ImGui::BeginChild(id, size, (g.CurrentWindow->Flags & ImGuiWindowFlags_ShowBorders) ? true : false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); } void ImGui::EndChildFrame() { ImGui::EndChild(); - ImGui::PopStyleVar(); + ImGui::PopStyleVar(2); ImGui::PopStyleColor(); } @@ -7310,7 +7311,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 return false; } draw_window = GetCurrentWindow(); - draw_window->DC.CursorPos += style.FramePadding; size.x -= draw_window->ScrollbarSizes.x; } else From e808b7cfcaefe6599b0ad7388980155d4ade15e9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Apr 2016 01:37:02 +0200 Subject: [PATCH 074/400] Style: removed WindowFillAlphaDefault which was confusing and redundant, baked into WindowBg color. Renamed TooltipBg > PopupBG. (#337) bg_alpha parameter of 5-parameters version of Begin() is an override, however that function may become obsolete someday. --- imgui.cpp | 55 ++++++++++++++++++++++---------------------------- imgui.h | 9 ++++----- imgui_demo.cpp | 11 +++------- 3 files changed, 31 insertions(+), 44 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4a32088d..eb809f2a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -152,6 +152,8 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. @@ -699,7 +701,6 @@ ImGuiStyle::ImGuiStyle() ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin() IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar @@ -714,8 +715,9 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); - Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + Colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f); Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.65f); Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input @@ -753,7 +755,6 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); - Colors[ImGuiCol_TooltipBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f); Colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } @@ -3138,9 +3139,8 @@ static ImRect GetVisibleRect() void ImGui::BeginTooltip() { - ImGuiState& g = *GImGui; ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; - ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, flags); + ImGui::Begin("##Tooltip", NULL, flags); } void ImGui::EndTooltip() @@ -3278,9 +3278,8 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.Size); // Recycle windows based on depth else ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame - float alpha = 1.0f; - bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags); + bool opened = ImGui::Begin(name, NULL, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) g.CurrentWindow->Flags &= ~ImGuiWindowFlags_ShowBorders; if (!opened) // opened can be 'false' when the popup is completely clipped (e.g. zero size display) @@ -3311,7 +3310,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_opened, ImGuiWindowFlags e } ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoSavedSettings; - bool opened = ImGui::Begin(name, p_opened, ImVec2(0.0f, 0.0f), -1.0f, flags); + bool opened = ImGui::Begin(name, p_opened, flags); if (!opened || (p_opened && !*p_opened)) // Opened can be 'false' when the popup is completely clipped (e.g. zero size display) { ImGui::EndPopup(); @@ -3391,8 +3390,7 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, char title[256]; ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s", window->Name, str_id); - const float alpha = 1.0f; - bool ret = ImGui::Begin(title, NULL, size, alpha, flags); + bool ret = ImGui::Begin(title, NULL, size, -1.0f, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; @@ -3692,10 +3690,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->RootWindow = g.CurrentWindowStack[root_idx]; window->RootNonPopupWindow = g.CurrentWindowStack[root_non_popup_idx]; // This is merely for displaying the TitleBgActive color. - // Default alpha - if (bg_alpha < 0.0f) - bg_alpha = style.WindowFillAlphaDefault; - // When reusing window again multiple times a frame, just append content (don't need to setup again) if (first_begin_of_the_frame) { @@ -3987,21 +3981,20 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f; // Window background - if (bg_alpha > 0.0f) - { - ImGuiCol col_idx; - if ((flags & ImGuiWindowFlags_ComboBox) != 0) - col_idx = ImGuiCol_ComboBg; - else if ((flags & ImGuiWindowFlags_Tooltip) != 0) - col_idx = ImGuiCol_TooltipBg; - else if ((flags & ImGuiWindowFlags_Popup) != 0) - col_idx = ImGuiCol_WindowBg; - else if ((flags & ImGuiWindowFlags_ChildWindow) != 0) - col_idx = ImGuiCol_ChildWindowBg; - else - col_idx = ImGuiCol_WindowBg; - window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, GetColorU32(col_idx, bg_alpha), window_rounding); - } + // Default alpha + ImGuiCol bg_color_idx = ImGuiCol_WindowBg; + if ((flags & ImGuiWindowFlags_ComboBox) != 0) + bg_color_idx = ImGuiCol_ComboBg; + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 || (flags & ImGuiWindowFlags_Popup) != 0) + bg_color_idx = ImGuiCol_PopupBg; + else if ((flags & ImGuiWindowFlags_ChildWindow) != 0) + bg_color_idx = ImGuiCol_ChildWindowBg; + ImVec4 bg_color = style.Colors[bg_color_idx]; + if (bg_alpha >= 0.0f) + bg_color.w = bg_alpha; + bg_color.w *= style.Alpha; + if (bg_color.w > 0.0f) + window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding); // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) @@ -4522,6 +4515,7 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_TextDisabled: return "TextDisabled"; case ImGuiCol_WindowBg: return "WindowBg"; case ImGuiCol_ChildWindowBg: return "ChildWindowBg"; + case ImGuiCol_PopupBg: return "PopupBg"; case ImGuiCol_Border: return "Border"; case ImGuiCol_BorderShadow: return "BorderShadow"; case ImGuiCol_FrameBg: return "FrameBg"; @@ -4559,7 +4553,6 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_PlotHistogram: return "PlotHistogram"; case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; - case ImGuiCol_TooltipBg: return "TooltipBg"; case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening"; } IM_ASSERT(0); @@ -8501,7 +8494,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) bool want_open = false, want_close = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { - // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers so menus feel more reactive. + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. bool moving_within_opened_triangle = false; if (g.HoveredWindow == window && g.OpenedPopupStack.Size > g.CurrentPopupStack.Size && g.OpenedPopupStack[g.CurrentPopupStack.Size].ParentWindow == window) { diff --git a/imgui.h b/imgui.h index 3d2e0277..c4834e79 100644 --- a/imgui.h +++ b/imgui.h @@ -114,7 +114,7 @@ namespace ImGui // Window IMGUI_API bool Begin(const char* name, bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // push window to the stack and start appending to it. see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). - IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // ". this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. + IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE. this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. IMGUI_API void End(); // finish appending to current window, pop it off the window stack. IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " @@ -546,8 +546,9 @@ enum ImGuiCol_ { ImGuiCol_Text, ImGuiCol_TextDisabled, - ImGuiCol_WindowBg, - ImGuiCol_ChildWindowBg, + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildWindowBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows ImGuiCol_Border, ImGuiCol_BorderShadow, ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input @@ -585,7 +586,6 @@ enum ImGuiCol_ ImGuiCol_PlotHistogram, ImGuiCol_PlotHistogramHovered, ImGuiCol_TextSelectedBg, - ImGuiCol_TooltipBg, ImGuiCol_ModalWindowDarkening, // darken entire screen when a modal window is active ImGuiCol_COUNT }; @@ -663,7 +663,6 @@ struct ImGuiStyle ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin() float IndentSpacing; // Horizontal indentation when e.g. entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f85eda53..64c60862 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -139,7 +139,6 @@ void ImGui::ShowTestWindow(bool* p_opened) static bool no_scrollbar = false; static bool no_collapse = false; static bool no_menu = false; - static float bg_alpha = -0.01f; // <0: default // Demonstrate the various window flags. Typically you would just use the default. ImGuiWindowFlags window_flags = 0; @@ -150,7 +149,8 @@ void ImGui::ShowTestWindow(bool* p_opened) if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; - if (!ImGui::Begin("ImGui Demo", p_opened, ImVec2(550,680), bg_alpha, window_flags)) + ImGui::SetNextWindowSize(ImVec2(550,680), ImGuiSetCond_FirstUseEver); + if (!ImGui::Begin("ImGui Demo", p_opened, window_flags)) { // Early out if the window is collapsed, as an optimization. ImGui::End(); @@ -211,10 +211,6 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Checkbox("No collapse", &no_collapse); ImGui::Checkbox("No menu", &no_menu); - ImGui::PushItemWidth(100); - ImGui::DragFloat("Window Fill Alpha", &bg_alpha, 0.005f, -0.01f, 1.0f, bg_alpha < 0.0f ? "(default)" : "%.3f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - ImGui::PopItemWidth(); - if (ImGui::TreeNode("Style")) { ImGui::ShowStyleEditor(); @@ -1561,7 +1557,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f); if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f; ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - ImGui::DragFloat("Window Fill Alpha Default", &style.WindowFillAlphaDefault, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::PopItemWidth(); ImGui::TreePop(); } @@ -1618,7 +1613,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) static ImGuiTextFilter filter; filter.Draw("Filter colors", 200); - ImGui::BeginChild("#colors", ImVec2(0, 300), true); + ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); ImGui::PushItemWidth(-160); ImGui::ColorEditMode(edit_mode); for (int i = 0; i < ImGuiCol_COUNT; i++) From 2ee76bbff64656a48fdb43b76f2f8494d9448873 Mon Sep 17 00:00:00 2001 From: cheriff Date: Tue, 5 Apr 2016 17:23:00 +1000 Subject: [PATCH 075/400] Trivial format string fix in demo --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 64c60862..a7268d48 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1496,7 +1496,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); } ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } - ImGui::Text("KeyMods: %s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text("KeyMods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("WantCaptureMouse: %s", io.WantCaptureMouse ? "true" : "false"); ImGui::Text("WantCaptureKeyboard: %s", io.WantCaptureKeyboard ? "true" : "false"); From 67b604412ba818165bdd81e57217584a9fed05b3 Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 5 Apr 2016 15:49:23 +0800 Subject: [PATCH 076/400] Remove local glfw3 lib for osx. (+1 squashed commit) Squashed commits: [34cc3b7] Adds osx example. (+6 squashed commits) Squashed commits: [20330f2] Uses glfw by brew install. [0427861] Renames imguiex folder name to imguiex-ios [f9e27e5] Renames ios_example to apple_example. [44f8fe3] Updates the glfw header/library path. [919f279] Renames target from imguiex to imguiex-ios since there is already a imguiex-osx target now. [24395f5] Adds osx example. --- .../{ios_example => apple_example}/.gitignore | 0 .../{ios_example => apple_example}/README.md | 11 +- .../imguiex-ios}/AppDelegate.h | 0 .../imguiex-ios}/AppDelegate.m | 0 .../imguiex-ios}/Base.lproj/LaunchScreen.xib | 0 .../imguiex-ios}/Base.lproj/Main.storyboard | 0 .../imguiex-ios}/GameViewController.h | 0 .../imguiex-ios}/GameViewController.m | 0 .../AppIcon.appiconset/Contents.json | 5 + .../icon_imgui_60@2x~iphone.png | Bin .../icon_imgui_60@3x~iphone.png | Bin .../icon_imgui_76@2x~ipad.png | Bin .../AppIcon.appiconset/icon_imgui_76~ipad.png | Bin .../imguiex-ios}/Info.plist | 0 .../imguiex-ios}/Shaders/Shader.fsh | 0 .../imguiex-ios}/Shaders/Shader.vsh | 0 .../imguiex-ios}/debug_hud.cpp | 0 .../imguiex-ios}/debug_hud.h | 0 .../imguiex-ios}/imgui_ex_icon.png | Bin .../imguiex-ios}/imgui_impl_ios.h | 0 .../imguiex-ios}/imgui_impl_ios.mm | 0 .../imguiex-ios}/main.m | 0 .../apple_example/imguiex-osx/AppDelegate.h | 15 ++ .../apple_example/imguiex-osx/AppDelegate.m | 26 +++ .../AppIcon.appiconset/Contents.json | 64 ++++++ .../AppIcon.appiconset/icon_imgui_180x180.png | Bin 0 -> 5953 bytes .../imguiex-osx/Assets.xcassets/Contents.json | 6 + examples/apple_example/imguiex-osx/Info.plist | 34 ++++ examples/apple_example/imguiex-osx/main.m | 13 ++ .../imguiex.xcodeproj/project.pbxproj | 192 ++++++++++++++++-- 30 files changed, 351 insertions(+), 15 deletions(-) rename examples/{ios_example => apple_example}/.gitignore (100%) rename examples/{ios_example => apple_example}/README.md (84%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/AppDelegate.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/AppDelegate.m (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Base.lproj/LaunchScreen.xib (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Base.lproj/Main.storyboard (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/GameViewController.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/GameViewController.m (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/Contents.json (93%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Info.plist (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Shaders/Shader.fsh (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Shaders/Shader.vsh (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/debug_hud.cpp (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/debug_hud.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/imgui_ex_icon.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/imgui_impl_ios.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/imgui_impl_ios.mm (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/main.m (100%) create mode 100644 examples/apple_example/imguiex-osx/AppDelegate.h create mode 100644 examples/apple_example/imguiex-osx/AppDelegate.m create mode 100644 examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/icon_imgui_180x180.png create mode 100644 examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json create mode 100644 examples/apple_example/imguiex-osx/Info.plist create mode 100644 examples/apple_example/imguiex-osx/main.m rename examples/{ios_example => apple_example}/imguiex.xcodeproj/project.pbxproj (66%) diff --git a/examples/ios_example/.gitignore b/examples/apple_example/.gitignore similarity index 100% rename from examples/ios_example/.gitignore rename to examples/apple_example/.gitignore diff --git a/examples/ios_example/README.md b/examples/apple_example/README.md similarity index 84% rename from examples/ios_example/README.md rename to examples/apple_example/README.md index a2ada955..c847f1a3 100644 --- a/examples/ios_example/README.md +++ b/examples/apple_example/README.md @@ -1,4 +1,4 @@ -# iOS example +# iOS / OSX example ## Introduction @@ -16,6 +16,13 @@ Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImG 0. Enter the name or the IP of your synergy host 0. If you had previously connected to a server, you may need to kill and re-start the app. +## How to Run on OSX + +* Make sure you have install `brew`, if not, please refer to [Homebrew Website](http://brew.sh) +* Run the command: `brew install glfw3` +* Double click `imguiex.xcodeproj` and select `imguiex-osx` scheme +* Click `Run` button + ## Notes and TODOs Things that would be nice but I didn't get around to doing: @@ -25,7 +32,7 @@ Things that would be nice but I didn't get around to doing: * Graceful disconnect/reconnect from uSynergy. * Copy/Paste not well-supported -## C++ on iOS +## C++ on iOS / OSX ImGui is a c++ library. If you want to include it directly, rename your Obj-C file to have the ".mm" extension. Alternatively, you can wrap your debug code in a C interface, this is what I am demonstrating here with the "debug_hud.h" interface. Either approach works, use whatever you prefer. diff --git a/examples/ios_example/imguiex/AppDelegate.h b/examples/apple_example/imguiex-ios/AppDelegate.h similarity index 100% rename from examples/ios_example/imguiex/AppDelegate.h rename to examples/apple_example/imguiex-ios/AppDelegate.h diff --git a/examples/ios_example/imguiex/AppDelegate.m b/examples/apple_example/imguiex-ios/AppDelegate.m similarity index 100% rename from examples/ios_example/imguiex/AppDelegate.m rename to examples/apple_example/imguiex-ios/AppDelegate.m diff --git a/examples/ios_example/imguiex/Base.lproj/LaunchScreen.xib b/examples/apple_example/imguiex-ios/Base.lproj/LaunchScreen.xib similarity index 100% rename from examples/ios_example/imguiex/Base.lproj/LaunchScreen.xib rename to examples/apple_example/imguiex-ios/Base.lproj/LaunchScreen.xib diff --git a/examples/ios_example/imguiex/Base.lproj/Main.storyboard b/examples/apple_example/imguiex-ios/Base.lproj/Main.storyboard similarity index 100% rename from examples/ios_example/imguiex/Base.lproj/Main.storyboard rename to examples/apple_example/imguiex-ios/Base.lproj/Main.storyboard diff --git a/examples/ios_example/imguiex/GameViewController.h b/examples/apple_example/imguiex-ios/GameViewController.h similarity index 100% rename from examples/ios_example/imguiex/GameViewController.h rename to examples/apple_example/imguiex-ios/GameViewController.h diff --git a/examples/ios_example/imguiex/GameViewController.m b/examples/apple_example/imguiex-ios/GameViewController.m similarity index 100% rename from examples/ios_example/imguiex/GameViewController.m rename to examples/apple_example/imguiex-ios/GameViewController.m diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 93% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/Contents.json rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/Contents.json index a05a29bb..06b60d8b 100644 --- a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/Contents.json @@ -63,6 +63,11 @@ "idiom" : "ipad", "filename" : "icon_imgui_76@2x~ipad.png", "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" } ], "info" : { diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png diff --git a/examples/ios_example/imguiex/Info.plist b/examples/apple_example/imguiex-ios/Info.plist similarity index 100% rename from examples/ios_example/imguiex/Info.plist rename to examples/apple_example/imguiex-ios/Info.plist diff --git a/examples/ios_example/imguiex/Shaders/Shader.fsh b/examples/apple_example/imguiex-ios/Shaders/Shader.fsh similarity index 100% rename from examples/ios_example/imguiex/Shaders/Shader.fsh rename to examples/apple_example/imguiex-ios/Shaders/Shader.fsh diff --git a/examples/ios_example/imguiex/Shaders/Shader.vsh b/examples/apple_example/imguiex-ios/Shaders/Shader.vsh similarity index 100% rename from examples/ios_example/imguiex/Shaders/Shader.vsh rename to examples/apple_example/imguiex-ios/Shaders/Shader.vsh diff --git a/examples/ios_example/imguiex/debug_hud.cpp b/examples/apple_example/imguiex-ios/debug_hud.cpp similarity index 100% rename from examples/ios_example/imguiex/debug_hud.cpp rename to examples/apple_example/imguiex-ios/debug_hud.cpp diff --git a/examples/ios_example/imguiex/debug_hud.h b/examples/apple_example/imguiex-ios/debug_hud.h similarity index 100% rename from examples/ios_example/imguiex/debug_hud.h rename to examples/apple_example/imguiex-ios/debug_hud.h diff --git a/examples/ios_example/imguiex/imgui_ex_icon.png b/examples/apple_example/imguiex-ios/imgui_ex_icon.png similarity index 100% rename from examples/ios_example/imguiex/imgui_ex_icon.png rename to examples/apple_example/imguiex-ios/imgui_ex_icon.png diff --git a/examples/ios_example/imguiex/imgui_impl_ios.h b/examples/apple_example/imguiex-ios/imgui_impl_ios.h similarity index 100% rename from examples/ios_example/imguiex/imgui_impl_ios.h rename to examples/apple_example/imguiex-ios/imgui_impl_ios.h diff --git a/examples/ios_example/imguiex/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm similarity index 100% rename from examples/ios_example/imguiex/imgui_impl_ios.mm rename to examples/apple_example/imguiex-ios/imgui_impl_ios.mm diff --git a/examples/ios_example/imguiex/main.m b/examples/apple_example/imguiex-ios/main.m similarity index 100% rename from examples/ios_example/imguiex/main.m rename to examples/apple_example/imguiex-ios/main.m diff --git a/examples/apple_example/imguiex-osx/AppDelegate.h b/examples/apple_example/imguiex-osx/AppDelegate.h new file mode 100644 index 00000000..33d199bb --- /dev/null +++ b/examples/apple_example/imguiex-osx/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// imguiex-osx +// +// Created by James Chen on 4/5/16. +// Copyright © 2016 Joel Davis. All rights reserved. +// + +#import + +@interface AppDelegate : NSObject + + +@end + diff --git a/examples/apple_example/imguiex-osx/AppDelegate.m b/examples/apple_example/imguiex-osx/AppDelegate.m new file mode 100644 index 00000000..59e877b3 --- /dev/null +++ b/examples/apple_example/imguiex-osx/AppDelegate.m @@ -0,0 +1,26 @@ +// +// AppDelegate.m +// imguiex-osx +// +// Created by James Chen on 4/5/16. +// Copyright © 2016 Joel Davis. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@property (weak) IBOutlet NSWindow *window; +@end + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Insert code here to initialize your application +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + // Insert code here to tear down your application +} + +@end diff --git a/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..b13908fc --- /dev/null +++ b/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,64 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon_imgui_180x180.png", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/icon_imgui_180x180.png b/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/icon_imgui_180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..f48b799dba2cf05b31924886eb4fc9d803ea4a83 GIT binary patch literal 5953 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 aW)oPOXB1N~w0~dYfLBm;#aac6u>S!7Vo}-v literal 0 HcmV?d00001 diff --git a/examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json b/examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json new file mode 100644 index 00000000..da4a164c --- /dev/null +++ b/examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/apple_example/imguiex-osx/Info.plist b/examples/apple_example/imguiex-osx/Info.plist new file mode 100644 index 00000000..ba1c2bb0 --- /dev/null +++ b/examples/apple_example/imguiex-osx/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Joel Davis. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/examples/apple_example/imguiex-osx/main.m b/examples/apple_example/imguiex-osx/main.m new file mode 100644 index 00000000..20b07313 --- /dev/null +++ b/examples/apple_example/imguiex-osx/main.m @@ -0,0 +1,13 @@ +// +// main.m +// imguiex-osx +// +// Created by James Chen on 4/5/16. +// Copyright © 2016 Joel Davis. All rights reserved. +// + +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} diff --git a/examples/ios_example/imguiex.xcodeproj/project.pbxproj b/examples/apple_example/imguiex.xcodeproj/project.pbxproj similarity index 66% rename from examples/ios_example/imguiex.xcodeproj/project.pbxproj rename to examples/apple_example/imguiex.xcodeproj/project.pbxproj index 26bcff49..652d15b6 100644 --- a/examples/ios_example/imguiex.xcodeproj/project.pbxproj +++ b/examples/apple_example/imguiex.xcodeproj/project.pbxproj @@ -9,6 +9,16 @@ /* Begin PBXBuildFile section */ 197E1E871B8943FE00E3FE6A /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E861B8943FE00E3FE6A /* imgui_draw.cpp */; }; 197E1E891B89443600E3FE6A /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E881B89443600E3FE6A /* imgui_demo.cpp */; }; + 1A1A0F231CB39FB50090F036 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A0F221CB39FB50090F036 /* AppDelegate.m */; }; + 1A1A0F281CB39FB50090F036 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A1A0F271CB39FB50090F036 /* Assets.xcassets */; }; + 1A1A0F301CB3A0DA0090F036 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E861B8943FE00E3FE6A /* imgui_draw.cpp */; }; + 1A1A0F311CB3A0DA0090F036 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC5861B2E64AB00C130BA /* imgui.cpp */; }; + 1A1A0F321CB3A0DE0090F036 /* uSynergy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6D1E39151B35EEF10017B40F /* uSynergy.c */; }; + 1A1A0F331CB3A0E10090F036 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E881B89443600E3FE6A /* imgui_demo.cpp */; }; + 1A1A0F341CB3A0EC0090F036 /* debug_hud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC5891B2E6A5500C130BA /* debug_hud.cpp */; }; + 1A1A0F481CB3A2E50090F036 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A0F391CB3A1B20090F036 /* main.cpp */; }; + 1A1A0F4A1CB3A5070090F036 /* imgui_impl_glfw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */; }; + 1A1A0F4E1CB3C54D0090F036 /* libglfw3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */; }; 6D1E39171B35EEF10017B40F /* uSynergy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6D1E39151B35EEF10017B40F /* uSynergy.c */; }; 6D2FC55A1B2E632000C130BA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC5591B2E632000C130BA /* main.m */; }; 6D2FC55D1B2E632000C130BA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC55C1B2E632000C130BA /* AppDelegate.m */; }; @@ -28,9 +38,18 @@ /* Begin PBXFileReference section */ 197E1E861B8943FE00E3FE6A /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = ../../imgui_draw.cpp; sourceTree = ""; }; 197E1E881B89443600E3FE6A /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../../imgui_demo.cpp; sourceTree = ""; }; + 1A1A0F1F1CB39FB50090F036 /* imguiex-osx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "imguiex-osx.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1A1A0F211CB39FB50090F036 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 1A1A0F221CB39FB50090F036 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 1A1A0F271CB39FB50090F036 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1A1A0F2C1CB39FB50090F036 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_impl_glfw.cpp; sourceTree = ""; }; + 1A1A0F381CB3A1B20090F036 /* imgui_impl_glfw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_glfw.h; sourceTree = ""; }; + 1A1A0F391CB3A1B20090F036 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libglfw3.dylib; path = /usr/local/lib/libglfw3.dylib; sourceTree = ""; }; 6D1E39151B35EEF10017B40F /* uSynergy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uSynergy.c; sourceTree = ""; }; 6D1E39161B35EEF10017B40F /* uSynergy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uSynergy.h; sourceTree = ""; }; - 6D2FC5541B2E632000C130BA /* imguiex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = imguiex.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 6D2FC5541B2E632000C130BA /* imguiex-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "imguiex-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 6D2FC5581B2E632000C130BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6D2FC5591B2E632000C130BA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 6D2FC55B1B2E632000C130BA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -54,6 +73,14 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 1A1A0F1C1CB39FB50090F036 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A1A0F4E1CB3C54D0090F036 /* libglfw3.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6D2FC5511B2E632000C130BA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -66,6 +93,38 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1A1A0F201CB39FB50090F036 /* imguiex-osx */ = { + isa = PBXGroup; + children = ( + 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */, + 1A1A0F351CB3A1B20090F036 /* opengl_example */, + 1A1A0F211CB39FB50090F036 /* AppDelegate.h */, + 1A1A0F221CB39FB50090F036 /* AppDelegate.m */, + 1A1A0F271CB39FB50090F036 /* Assets.xcassets */, + 1A1A0F2C1CB39FB50090F036 /* Info.plist */, + 1A1A0F241CB39FB50090F036 /* Supporting Files */, + ); + path = "imguiex-osx"; + sourceTree = ""; + }; + 1A1A0F241CB39FB50090F036 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 1A1A0F351CB3A1B20090F036 /* opengl_example */ = { + isa = PBXGroup; + children = ( + 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */, + 1A1A0F381CB3A1B20090F036 /* imgui_impl_glfw.h */, + 1A1A0F391CB3A1B20090F036 /* main.cpp */, + ); + name = opengl_example; + path = ../../opengl_example; + sourceTree = ""; + }; 6D1E39141B35EEF10017B40F /* usynergy */ = { isa = PBXGroup; children = ( @@ -81,7 +140,8 @@ children = ( 6D1E39141B35EEF10017B40F /* usynergy */, 6D2FC5841B2E648D00C130BA /* imgui */, - 6D2FC5561B2E632000C130BA /* imguiex */, + 6D2FC5561B2E632000C130BA /* imguiex-ios */, + 1A1A0F201CB39FB50090F036 /* imguiex-osx */, 6D2FC5551B2E632000C130BA /* Products */, ); sourceTree = ""; @@ -89,12 +149,13 @@ 6D2FC5551B2E632000C130BA /* Products */ = { isa = PBXGroup; children = ( - 6D2FC5541B2E632000C130BA /* imguiex.app */, + 6D2FC5541B2E632000C130BA /* imguiex-ios.app */, + 1A1A0F1F1CB39FB50090F036 /* imguiex-osx.app */, ); name = Products; sourceTree = ""; }; - 6D2FC5561B2E632000C130BA /* imguiex */ = { + 6D2FC5561B2E632000C130BA /* imguiex-ios */ = { isa = PBXGroup; children = ( 6D2FC5811B2E63A100C130BA /* imgui_impl_ios.mm */, @@ -113,7 +174,7 @@ 6D2FC56A1B2E632000C130BA /* LaunchScreen.xib */, 6D2FC5571B2E632000C130BA /* Supporting Files */, ); - path = imguiex; + path = "imguiex-ios"; sourceTree = ""; }; 6D2FC5571B2E632000C130BA /* Supporting Files */ = { @@ -141,9 +202,26 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 6D2FC5531B2E632000C130BA /* imguiex */ = { + 1A1A0F1E1CB39FB50090F036 /* imguiex-osx */ = { isa = PBXNativeTarget; - buildConfigurationList = 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex" */; + buildConfigurationList = 1A1A0F2F1CB39FB50090F036 /* Build configuration list for PBXNativeTarget "imguiex-osx" */; + buildPhases = ( + 1A1A0F1B1CB39FB50090F036 /* Sources */, + 1A1A0F1C1CB39FB50090F036 /* Frameworks */, + 1A1A0F1D1CB39FB50090F036 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "imguiex-osx"; + productName = "imguiex-osx"; + productReference = 1A1A0F1F1CB39FB50090F036 /* imguiex-osx.app */; + productType = "com.apple.product-type.application"; + }; + 6D2FC5531B2E632000C130BA /* imguiex-ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex-ios" */; buildPhases = ( 6D2FC5501B2E632000C130BA /* Sources */, 6D2FC5511B2E632000C130BA /* Frameworks */, @@ -153,9 +231,9 @@ ); dependencies = ( ); - name = imguiex; + name = "imguiex-ios"; productName = imguiex; - productReference = 6D2FC5541B2E632000C130BA /* imguiex.app */; + productReference = 6D2FC5541B2E632000C130BA /* imguiex-ios.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -167,6 +245,9 @@ LastUpgradeCheck = 0630; ORGANIZATIONNAME = "Joel Davis"; TargetAttributes = { + 1A1A0F1E1CB39FB50090F036 = { + CreatedOnToolsVersion = 7.3; + }; 6D2FC5531B2E632000C130BA = { CreatedOnToolsVersion = 6.3.2; }; @@ -185,12 +266,21 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 6D2FC5531B2E632000C130BA /* imguiex */, + 6D2FC5531B2E632000C130BA /* imguiex-ios */, + 1A1A0F1E1CB39FB50090F036 /* imguiex-osx */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 1A1A0F1D1CB39FB50090F036 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A1A0F281CB39FB50090F036 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6D2FC5521B2E632000C130BA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -206,6 +296,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 1A1A0F1B1CB39FB50090F036 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A1A0F301CB3A0DA0090F036 /* imgui_draw.cpp in Sources */, + 1A1A0F311CB3A0DA0090F036 /* imgui.cpp in Sources */, + 1A1A0F331CB3A0E10090F036 /* imgui_demo.cpp in Sources */, + 1A1A0F341CB3A0EC0090F036 /* debug_hud.cpp in Sources */, + 1A1A0F481CB3A2E50090F036 /* main.cpp in Sources */, + 1A1A0F321CB3A0DE0090F036 /* uSynergy.c in Sources */, + 1A1A0F231CB39FB50090F036 /* AppDelegate.m in Sources */, + 1A1A0F4A1CB3A5070090F036 /* imgui_impl_glfw.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6D2FC5501B2E632000C130BA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -244,6 +349,54 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 1A1A0F2D1CB39FB50090F036 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../", + /usr/local/include, + ); + INFOPLIST_FILE = "imguiex-osx/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.imguiex.imguiex-osx"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Debug; + }; + 1A1A0F2E1CB39FB50090F036 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../", + /usr/local/include, + ); + INFOPLIST_FILE = "imguiex-osx/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.imguiex.imguiex-osx"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Release; + }; 6D2FC5791B2E632000C130BA /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -280,11 +433,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ""; }; name = Debug; }; @@ -318,10 +473,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ""; VALIDATE_PRODUCT = YES; }; name = Release; @@ -330,7 +487,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = imguiex/Info.plist; + INFOPLIST_FILE = "imguiex-ios/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -340,7 +497,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = imguiex/Info.plist; + INFOPLIST_FILE = "imguiex-ios/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -349,6 +506,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 1A1A0F2F1CB39FB50090F036 /* Build configuration list for PBXNativeTarget "imguiex-osx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1A1A0F2D1CB39FB50090F036 /* Debug */, + 1A1A0F2E1CB39FB50090F036 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 6D2FC54F1B2E632000C130BA /* Build configuration list for PBXProject "imguiex" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -358,7 +524,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex" */ = { + 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex-ios" */ = { isa = XCConfigurationList; buildConfigurations = ( 6D2FC57C1B2E632000C130BA /* Debug */, From 71b981d05fbf077c0d5b9cfeffa7a3de979810c7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 5 Apr 2016 22:50:23 +0200 Subject: [PATCH 077/400] Examples: Apple: Readme tweaks (#575 #247) --- examples/README.txt | 6 +++--- examples/apple_example/README.md | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 0259ae64..df6fe879 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -63,9 +63,9 @@ directx11_example/ DirectX11 example, Windows only. This is quite long and tedious, because: DirectX11. -ios_example/ - iOS example. - Using Synergy to access keyboard/mouse data from server computer. +apple_example/ + OSX & iOS example. + On iOS, Using Synergy to access keyboard/mouse data from server computer. Synergy keyboard integration is rather hacky. sdl_opengl_example/ diff --git a/examples/apple_example/README.md b/examples/apple_example/README.md index c847f1a3..1d2355e0 100644 --- a/examples/apple_example/README.md +++ b/examples/apple_example/README.md @@ -2,19 +2,19 @@ ## Introduction -This example is the default XCode "OpenGL" example code, modified to support ImGui and [Synergy](http://synergy-project.org/). +This example is the default XCode "OpenGL" example code, modified to support ImGui (and [Synergy](http://synergy-project.org/) to share mouse/keyboard with an iOS device). It is a rather complex example because of all of the faff required to get an XCode/iOS application running. Refer to the regular OpenGL examples if you want to learn about integrating ImGui. Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImGui without it. Synergy includes a "uSynergy" library that allows embedding a synergy client, this is what is used here. ImGui supports "TouchPadding", and this is enabled when Synergy is not active. -## How to Use +## How to Use on iOS -0. In Synergy, go to Preferences, and uncheck "Use SSL encryption" -0. Run the example app. -0. Tap the "servername" button in the corner -0. Enter the name or the IP of your synergy host -0. If you had previously connected to a server, you may need to kill and re-start the app. +* In Synergy, go to Preferences, and uncheck "Use SSL encryption" +* Run the example app. +* Tap the "servername" button in the corner +* Enter the name or the IP of your synergy host +* If you had previously connected to a server, you may need to kill and re-start the app. ## How to Run on OSX @@ -33,6 +33,7 @@ Things that would be nice but I didn't get around to doing: * Copy/Paste not well-supported ## C++ on iOS / OSX + ImGui is a c++ library. If you want to include it directly, rename your Obj-C file to have the ".mm" extension. Alternatively, you can wrap your debug code in a C interface, this is what I am demonstrating here with the "debug_hud.h" interface. Either approach works, use whatever you prefer. From 319e288eef920d39916dd6e250eec31047f91a5b Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 5 Apr 2016 23:08:21 +0200 Subject: [PATCH 078/400] Update README.md --- examples/apple_example/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/apple_example/README.md b/examples/apple_example/README.md index 1d2355e0..339f6bf8 100644 --- a/examples/apple_example/README.md +++ b/examples/apple_example/README.md @@ -2,9 +2,9 @@ ## Introduction -This example is the default XCode "OpenGL" example code, modified to support ImGui (and [Synergy](http://synergy-project.org/) to share mouse/keyboard with an iOS device). +This example is the default XCode "OpenGL" example code, modified to support ImGui and [Synergy](http://synergy-project.org/) to share mouse/keyboard on an iOS device. -It is a rather complex example because of all of the faff required to get an XCode/iOS application running. Refer to the regular OpenGL examples if you want to learn about integrating ImGui. +It is a rather complex and messy example because of all of the faff required to get an XCode/iOS application running. Refer to the regular OpenGL examples if you want to learn about integrating ImGui. **The opengl3_example/ should also work on OS X and is much simpler.** This is an integration for iOS with Synergy. Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImGui without it. Synergy includes a "uSynergy" library that allows embedding a synergy client, this is what is used here. ImGui supports "TouchPadding", and this is enabled when Synergy is not active. @@ -16,7 +16,7 @@ Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImG * Enter the name or the IP of your synergy host * If you had previously connected to a server, you may need to kill and re-start the app. -## How to Run on OSX +## How to Build on OSX * Make sure you have install `brew`, if not, please refer to [Homebrew Website](http://brew.sh) * Run the command: `brew install glfw3` From 31852e1d05007f6a880d5249445af6bde3752485 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Apr 2016 11:11:30 +0200 Subject: [PATCH 079/400] Silence borderline warning with -Werror=strict-overflow Error: assuming signed overflow does not occur when assuming that (X - c) > X is always false [-Werror=strict-overflow] --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index eb809f2a..9410376f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1652,7 +1652,7 @@ ImGuiWindow* ImGui::GetParentWindow() { ImGuiState& g = *GImGui; IM_ASSERT(g.CurrentWindowStack.Size >= 2); - return g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; + return g.CurrentWindowStack[(unsigned int)g.CurrentWindowStack.Size - 2]; } void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) From 4c25de950cfb1ef55aa2643b116a752aeba830b8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 9 Apr 2016 17:46:38 +0200 Subject: [PATCH 080/400] Warning fixes for clang. Using int64_t, may be an issue? --- imgui.cpp | 8 ++++---- imgui.h | 5 +++-- imgui_demo.cpp | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9410376f..efee251a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2339,9 +2339,9 @@ static void AddDrawListToRenderList(ImVector& out_render_list, ImDr // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = 2 bytes = 64K vertices) // If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly. - IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Sanity check. Bug or mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. - IM_ASSERT((unsigned long long int)draw_list->_VtxCurrentIdx <= ((unsigned long long int)1L << (sizeof(ImDrawIdx)*8))); // Too many vertices in same ImDrawList. See comment above. - + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Sanity check. Bug or mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + IM_ASSERT((int64_t)draw_list->_VtxCurrentIdx <= ((int64_t)1L << (sizeof(ImDrawIdx)*8))); // Too many vertices in same ImDrawList. See comment above. + out_render_list.push_back(draw_list); GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size; GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size; @@ -7098,9 +7098,9 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; } -static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; } static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } #ifdef __APPLE__ // FIXME: Move setting to IO structure +static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; } static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } #else static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } diff --git a/imgui.h b/imgui.h index c4834e79..660d3f08 100644 --- a/imgui.h +++ b/imgui.h @@ -315,7 +315,7 @@ namespace ImGui IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layouting purpose IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); - IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened. + IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node/collapsing header to be opened. // Widgets: Selectable / Lists IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height @@ -890,6 +890,7 @@ struct ImGuiTextFilter int CountGrep; ImGuiTextFilter(const char* default_filter = ""); + ~ImGuiTextFilter() {} void Clear() { InputBuf[0] = 0; Build(); } bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build bool PassFilter(const char* text, const char* text_end = NULL) const; @@ -1152,7 +1153,7 @@ struct ImDrawList // Stateful path API, add points then finish with PathFill() or PathStroke() inline void PathClear() { _Path.resize(0); } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } - inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || _Path[_Path.Size-1].x != pos.x || _Path[_Path.Size-1].y != pos.y) _Path.push_back(pos); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } inline void PathFill(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col, true); PathClear(); } inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness, true); PathClear(); } IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a7268d48..83f38008 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2295,12 +2295,12 @@ static void ShowExampleAppPropertyEditor(bool* opened) { ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. ImGui::AlignFirstTextHeightToWidgets(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. - bool opened = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + bool is_opened = ImGui::TreeNode("Object", "%s_%u", prefix, uid); ImGui::NextColumn(); ImGui::AlignFirstTextHeightToWidgets(); ImGui::Text("my sailor is rich"); ImGui::NextColumn(); - if (opened) + if (is_opened) { static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; for (int i = 0; i < 8; i++) From 95cbcdca3fcf84bf94b3bb4374d884b1d4bc5db0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 9 Apr 2016 17:46:48 +0200 Subject: [PATCH 081/400] Version 1.48 --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index efee251a..191cc059 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (main code and documentation) // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index 660d3f08..c353e97e 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (headers) // See imgui.cpp file for documentation. @@ -16,7 +16,7 @@ #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.48 WIP" +#define IMGUI_VERSION "1.48" // Define attributes of all API symbols declarations, e.g. for DLL under Windows. #ifndef IMGUI_API diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 83f38008..d469473a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (demo code) // Don't remove this file from your project! It is useful reference code that you can execute. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 95871b60..533ecdae 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (drawing and font code) // Contains implementation for diff --git a/imgui_internal.h b/imgui_internal.h index 0f654a54..3dd17e64 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (internals) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! From 1588eda1ac70f8ea88a1b639858b31b59bdb93ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 9 Apr 2016 19:10:42 +0200 Subject: [PATCH 082/400] Version 1.49 WIP --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 191cc059..1cca7e92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (main code and documentation) // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index c353e97e..ac21c4ab 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (headers) // See imgui.cpp file for documentation. @@ -16,7 +16,7 @@ #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.48" +#define IMGUI_VERSION "1.49 WIP" // Define attributes of all API symbols declarations, e.g. for DLL under Windows. #ifndef IMGUI_API diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d469473a..146df300 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (demo code) // Don't remove this file from your project! It is useful reference code that you can execute. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 533ecdae..1d268561 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (drawing and font code) // Contains implementation for diff --git a/imgui_internal.h b/imgui_internal.h index 3dd17e64..e886ff1b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (internals) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! From 4466a7b3b0261900ce9e610eb026c597b09e7d60 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 11 Apr 2016 18:33:16 +0200 Subject: [PATCH 083/400] Examples: DirectX9: save/restore some more device state. --- examples/directx9_example/imgui_impl_dx9.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 17f4f078..813d58ef 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -53,6 +53,15 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) return; } + // Backup some DX9 state (not all!) + // FIXME: Backup/restore everything else + D3DRENDERSTATETYPE last_render_state_to_backup[] = { D3DRS_CULLMODE, D3DRS_LIGHTING, D3DRS_ZENABLE, D3DRS_ALPHABLENDENABLE, D3DRS_ALPHATESTENABLE, D3DRS_BLENDOP, D3DRS_SRCBLEND, D3DRS_DESTBLEND, D3DRS_SCISSORTESTENABLE }; + DWORD last_render_state_values[ARRAYSIZE(last_render_state_to_backup)] = { 0 }; + IDirect3DPixelShader9* last_ps; g_pd3dDevice->GetPixelShader( &last_ps ); + IDirect3DVertexShader9* last_vs; g_pd3dDevice->GetVertexShader( &last_vs ); + for (int n = 0; n < ARRAYSIZE(last_render_state_to_backup); n++) + g_pd3dDevice->GetRenderState(last_render_state_to_backup[n], &last_render_state_values[n]); + // Copy and convert all vertices into a single contiguous buffer CUSTOMVERTEX* vtx_dst; ImDrawIdx* idx_dst; @@ -91,8 +100,8 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false ); g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false ); g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); - g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false ); + g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true ); @@ -137,6 +146,12 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) } vtx_offset += cmd_list->VtxBuffer.size(); } + + // Restore some modified DX9 state (not all!) + g_pd3dDevice->SetPixelShader( last_ps ); + g_pd3dDevice->SetVertexShader( last_vs ); + for (int n = 0; n < ARRAYSIZE(last_render_state_to_backup); n++) + g_pd3dDevice->SetRenderState(last_render_state_to_backup[n], last_render_state_values[n]); } IMGUI_API LRESULT ImGui_ImplDX9_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 006934fd1560963e9d9c1a04bb3450cee8042b21 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 12 Apr 2016 22:36:51 +0200 Subject: [PATCH 084/400] Todo items + not using function called isblank() because it may be a macro in some C library --- imgui.cpp | 4 +++- imgui.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1cca7e92..512f18fb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -534,6 +534,7 @@ - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation). - style/opt: PopStyleVar could be optimized by having GetStyleVar returns the type, using a table mapping stylevar enum to data type. - style: global scale setting. + - style: WindowPadding needs to be EVEN needs the 0.5 multiplier probably have a subtle effect on clip rectangle - text: simple markup language for color change? - font: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier. - font: helper to add glyph redirect/replacements (e.g. redirect alternate apostrophe unicode code points to ascii one, etc.) @@ -558,7 +559,8 @@ - remote: make a system like RemoteImGui first-class citizen/project (#75) !- demo: custom render demo pushes a clipping rectangle past parent window bounds. expose ImGui::PushClipRect() from imgui_internal.h? - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - - examples: directx9/directx11: save/restore device state more thoroughly. + - examples: directx9: save/restore device state more thoroughly. + - examples: window minimize, maximize (#583) - optimization: use another hash function than crc32, e.g. FNV1a - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimization: turn some the various stack vectors into statically-sized arrays diff --git a/imgui.h b/imgui.h index ac21c4ab..685de3c3 100644 --- a/imgui.h +++ b/imgui.h @@ -880,8 +880,8 @@ struct ImGuiTextFilter const char* end() const { return e; } bool empty() const { return b == e; } char front() const { return *b; } - static bool isblank(char c) { return c == ' ' || c == '\t'; } - void trim_blanks() { while (b < e && isblank(*b)) b++; while (e > b && isblank(*(e-1))) e--; } + static bool is_blank(char c) { return c == ' ' || c == '\t'; } + void trim_blanks() { while (b < e && is_blank(*b)) b++; while (e > b && is_blank(*(e-1))) e--; } IMGUI_API void split(char separator, ImVector& out); }; From 1612ca071be21ff0f09f9dd8309fc8a7e44667fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 13 Apr 2016 00:15:58 +0200 Subject: [PATCH 085/400] Examples: SDL: Initialize video+timer subsystem only. --- examples/sdl_opengl3_example/main.cpp | 2 +- examples/sdl_opengl_example/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/sdl_opengl3_example/main.cpp b/examples/sdl_opengl3_example/main.cpp index 21cc8f2a..94ef6594 100644 --- a/examples/sdl_opengl3_example/main.cpp +++ b/examples/sdl_opengl3_example/main.cpp @@ -10,7 +10,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; diff --git a/examples/sdl_opengl_example/main.cpp b/examples/sdl_opengl_example/main.cpp index e9574e2f..f42e7faf 100644 --- a/examples/sdl_opengl_example/main.cpp +++ b/examples/sdl_opengl_example/main.cpp @@ -10,7 +10,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; From d5eb87d0a22b1232ef57d5ecf742cd3d9c53c437 Mon Sep 17 00:00:00 2001 From: Sergej Reich Date: Wed, 13 Apr 2016 02:01:18 +0200 Subject: [PATCH 086/400] Fix font config propagation in FontFromMemoryCompressedTTF() --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1d268561..5db88c62 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1204,7 +1204,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_d ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); IM_ASSERT(font_cfg.FontData == NULL); font_cfg.FontDataOwnedByAtlas = true; - return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, font_cfg_template, glyph_ranges); + return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); } ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) From ce613675207540d097f549f9e71d6cecdf0a1af0 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 18 Apr 2016 16:33:04 +0200 Subject: [PATCH 087/400] Update README.md - binaries --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 101cafc3..32f3eedb 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Demo ---- You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download Windows binaries of the demo app here. -- [imgui-demo-binaries-20151226.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20151226.zip) (Windows binaries, ImGui 1.47 2015/12/26, 4 executables, 515 KB) +- [imgui-demo-binaries-20151226.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20160410.zip) (Windows binaries, ImGui 1.48+ 2016/04/10, 4 executables, 534 KB) Gallery From fec7dc22a9879b6ab62d1763256ffcde16a41ec4 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 18 Apr 2016 16:33:49 +0200 Subject: [PATCH 088/400] Update README.md - binaries --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32f3eedb..88c7f4e3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Demo ---- You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download Windows binaries of the demo app here. -- [imgui-demo-binaries-20151226.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20160410.zip) (Windows binaries, ImGui 1.48+ 2016/04/10, 4 executables, 534 KB) +- [imgui-demo-binaries-20160410.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20160410.zip) (Windows binaries, ImGui 1.48+ 2016/04/10, 4 executables, 534 KB) Gallery From d92f1deff86e86b3f2835a7a6ac242ab7f5d08be Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 Apr 2016 19:04:42 +0200 Subject: [PATCH 089/400] ImDrawList: Added AddQuad(), AddQuadFilled() helpers. --- imgui.h | 4 +++- imgui_draw.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 685de3c3..7b6ba490 100644 --- a/imgui.h +++ b/imgui.h @@ -707,7 +707,7 @@ struct ImGuiIO ImVec2 DisplayVisibleMin; // (0.0f,0.0f) // If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area. ImVec2 DisplayVisibleMax; // (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize - // Advanced/subtle behaviors + // Advanced/subtle behaviors bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl bool DoubleClickSelectsWord; // = defined(__APPLE__) // OS X style: Double click selects by word instead of selecting whole text @@ -1139,6 +1139,8 @@ struct ImDrawList IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F, float thickness = 1.0f); // a: upper-left, b: lower-right IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); + IMGUI_API void AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col); IMGUI_API void AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness = 1.0f); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5db88c62..07aa6d27 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -823,6 +823,30 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left); } +void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness) +{ + if ((col >> 24) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathLineTo(d); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col) +{ + if ((col >> 24) == 0) + return; + + PathLineTo(a); + PathLineTo(b); + PathLineTo(c); + PathLineTo(d); + PathFill(col); +} + void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness) { if ((col >> 24) == 0) From fc3b8d0a5616c7cda1f010ed7e036d01711c87bf Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 19 Apr 2016 18:31:25 +0200 Subject: [PATCH 090/400] Relative order of Child windows creation is preserved during sort (#595) --- imgui.cpp | 7 ++++++- imgui_internal.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 512f18fb..876ff6f7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1575,6 +1575,7 @@ ImGuiWindow::ImGuiWindow(const char* name) MoveID = GetID("#MOVE"); Flags = 0; + IndexWithinParent = 0; PosFloat = Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f); @@ -2305,7 +2306,7 @@ static int ChildWindowComparer(const void* lhs, const void* rhs) return d; if (int d = (a->Flags & ImGuiWindowFlags_ComboBox) - (b->Flags & ImGuiWindowFlags_ComboBox)) return d; - return 0; + return (a->IndexWithinParent - b->IndexWithinParent); } static void AddWindowToSortedBuffer(ImVector& out_sorted_windows, ImGuiWindow* window) @@ -3696,6 +3697,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (first_begin_of_the_frame) { window->Active = true; + window->IndexWithinParent = 0; window->BeginCount = 0; window->DrawList->Clear(); window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); @@ -3826,7 +3828,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Position child window if (flags & ImGuiWindowFlags_ChildWindow) + { + window->IndexWithinParent = parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); + } if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) { window->Pos = window->PosFloat = parent_window->DC.CursorPos; diff --git a/imgui_internal.h b/imgui_internal.h index e886ff1b..a5ca7e64 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -596,6 +596,7 @@ struct IMGUI_API ImGuiWindow char* Name; ImGuiID ID; ImGuiWindowFlags Flags; + int IndexWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. ImVec2 PosFloat; ImVec2 Pos; // Position rounded-up to nearest pixel ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) From ab4a69bcd46efeabaf24829b823eff52386e769b Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 19 Apr 2016 18:31:40 +0200 Subject: [PATCH 091/400] Comments --- imgui_internal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index a5ca7e64..e49c63b0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -594,8 +594,8 @@ struct IMGUI_API ImGuiDrawContext struct IMGUI_API ImGuiWindow { char* Name; - ImGuiID ID; - ImGuiWindowFlags Flags; + ImGuiID ID; // == ImHash(Name) + ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ int IndexWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. ImVec2 PosFloat; ImVec2 Pos; // Position rounded-up to nearest pixel @@ -637,8 +637,8 @@ struct IMGUI_API ImGuiWindow ImGuiStorage StateStorage; float FontWindowScale; // Scale multiplier per-window ImDrawList* DrawList; - ImGuiWindow* RootWindow; - ImGuiWindow* RootNonPopupWindow; + ImGuiWindow* RootWindow; // If we are a child window, this is pointing to the first non-child parent window. Else point to ourself. + ImGuiWindow* RootNonPopupWindow; // If we are a child widnow, this is pointing to the first non-child non-popup parent window. Else point to ourself. // Focus int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() From 559963e832c6d69e78e7525c5f305cb9f9be16b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 20 Apr 2016 20:49:49 +0200 Subject: [PATCH 092/400] Examples: Apple/iOS: lowered xcode project deployment target from 10.7 to 10.11 (#598, #575) --- examples/apple_example/imguiex.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/apple_example/imguiex.xcodeproj/project.pbxproj b/examples/apple_example/imguiex.xcodeproj/project.pbxproj index 652d15b6..5d7776de 100644 --- a/examples/apple_example/imguiex.xcodeproj/project.pbxproj +++ b/examples/apple_example/imguiex.xcodeproj/project.pbxproj @@ -366,7 +366,7 @@ INFOPLIST_FILE = "imguiex-osx/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; LIBRARY_SEARCH_PATHS = /usr/local/lib; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.imguiex.imguiex-osx"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; @@ -389,7 +389,7 @@ INFOPLIST_FILE = "imguiex-osx/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; LIBRARY_SEARCH_PATHS = /usr/local/lib; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.imguiex.imguiex-osx"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; From 7ce6c18bbe662e9c6a80dd6c702952152a166e33 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 21 Apr 2016 09:55:02 +0200 Subject: [PATCH 093/400] Refactored CloseWindowButton() into a CloseButton() helper declared in imgui_internal.h (#600) --- imgui.cpp | 21 ++++++++++----------- imgui_internal.h | 1 + 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 876ff6f7..6b6d5af2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -633,7 +633,6 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window); static void ClearSetNextWindowData(); static void CheckStacksSize(ImGuiWindow* window, bool write); static void Scrollbar(ImGuiWindow* window, bool horizontal); -static bool CloseWindowButton(bool* p_opened); static void AddDrawListToRenderList(ImVector& out_render_list, ImDrawList* draw_list); static void AddWindowToRenderList(ImVector& out_render_list, ImGuiWindow* window); @@ -4082,7 +4081,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ if (!(flags & ImGuiWindowFlags_NoTitleBar)) { if (p_opened != NULL) - CloseWindowButton(p_opened); + { + const float pad = 2.0f; + const float rad = (window->TitleBarHeight() - pad*2.0f) * 0.5f; + if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad)) + *p_opened = false; + } const ImVec2 text_size = CalcTextSize(name, NULL, true); if (!(flags & ImGuiWindowFlags_NoCollapse)) @@ -5389,13 +5393,11 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) } // Upper-right button to close a window. -static bool CloseWindowButton(bool* p_opened) +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) { ImGuiWindow* window = ImGui::GetCurrentWindow(); - const ImGuiID id = window->GetID("#CLOSE"); - const float size = window->TitleBarHeight() - 4.0f; - const ImRect bb(window->Rect().GetTR() + ImVec2(-2.0f-size,2.0f), window->Rect().GetTR() + ImVec2(-2.0f,2.0f+size)); + const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius)); bool hovered, held; bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); @@ -5403,18 +5405,15 @@ static bool CloseWindowButton(bool* p_opened) // Render const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); const ImVec2 center = bb.GetCenter(); - window->DrawList->AddCircleFilled(center, ImMax(2.0f,size*0.5f), col, 16); + window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), col, 12); - const float cross_extent = (size * 0.5f * 0.7071f) - 1.0f; + const float cross_extent = (radius * 0.7071f) - 1.0f; if (hovered) { window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), ImGui::GetColorU32(ImGuiCol_Text)); window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), ImGui::GetColorU32(ImGuiCol_Text)); } - if (p_opened != NULL && pressed) - *p_opened = false; - return pressed; } diff --git a/imgui_internal.h b/imgui_internal.h index e49c63b0..c105a485 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -716,6 +716,7 @@ namespace ImGui IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); + IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); IMGUI_API bool SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags = 0); IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power); From 29e259a43cbafddfed5b14a2c73feac89fb6f744 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 22 Apr 2016 08:38:56 +0200 Subject: [PATCH 094/400] InputText() clipping cursor rendering in case it gets out of the box (which can be forced w/ ImGuiInputTextFlags_NoHorizontalScroll) (#601) --- imgui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6b6d5af2..40754cc8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7797,10 +7797,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf, buf+edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect); // Draw blinking cursor - ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll; bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f; - if (cursor_is_visible) - draw_window->DrawList->AddLine(cursor_screen_pos + ImVec2(0.0f,-g.FontSize+0.5f), cursor_screen_pos + ImVec2(0.0f,-1.5f), GetColorU32(ImGuiCol_Text)); + ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll; + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x, cursor_screen_pos.y-1.5f); + if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.Max, GetColorU32(ImGuiCol_Text)); // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (is_editable) From fe73a23cf58a62f0de54d73a16d2beeee17215a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 22 Apr 2016 19:58:10 +0200 Subject: [PATCH 095/400] ImFont: Added RenderChar() helper. --- imgui.h | 1 + imgui_draw.cpp | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/imgui.h b/imgui.h index 7b6ba490..4c7c8e3f 100644 --- a/imgui.h +++ b/imgui.h @@ -1324,6 +1324,7 @@ struct ImFont // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; IMGUI_API void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawList* draw_list, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 07aa6d27..2c421556 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1940,6 +1940,22 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons return text_size; } +void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const +{ + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded. + return; + if (const Glyph* glyph = FindGlyph(c)) + { + float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + pos.x = (float)(int)pos.x + DisplayOffset.x; + pos.y = (float)(int)pos.y + DisplayOffset.y; + ImVec2 pos_tl(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale); + ImVec2 pos_br(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale); + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(pos_tl, pos_br, ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); + } +} + void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawList* draw_list, float wrap_width, bool cpu_fine_clip) const { if (!text_end) @@ -2034,11 +2050,11 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re if (c != ' ' && c != '\t') { // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w - float y1 = (float)(y + glyph->Y0 * scale); - float y2 = (float)(y + glyph->Y1 * scale); + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; - float x1 = (float)(x + glyph->X0 * scale); - float x2 = (float)(x + glyph->X1 * scale); + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; if (x1 <= clip_rect.z && x2 >= clip_rect.x) { // Render a character From 44fb99542fc394907bca82d3baef4c5105dd047d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 Apr 2016 11:09:56 +0200 Subject: [PATCH 096/400] ImFont: RenderText() useful directly without ImDrawList::AddText().. Changed prototype. Reserving vertices after skipping non-visible lead. --- imgui.cpp | 6 +++++- imgui.h | 4 ++-- imgui_draw.cpp | 50 +++++++++++++++++++++----------------------------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 40754cc8..4944a288 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2339,9 +2339,13 @@ static void AddDrawListToRenderList(ImVector& out_render_list, ImDr return; } + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + IM_ASSERT(draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = 2 bytes = 64K vertices) // If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly. - IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Sanity check. Bug or mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. IM_ASSERT((int64_t)draw_list->_VtxCurrentIdx <= ((int64_t)1L << (sizeof(ImDrawIdx)*8))); // Too many vertices in same ImDrawList. See comment above. out_render_list.push_back(draw_list); diff --git a/imgui.h b/imgui.h index 4c7c8e3f..0389269c 100644 --- a/imgui.h +++ b/imgui.h @@ -1182,9 +1182,9 @@ struct ImDrawList IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); - inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col){ _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } IMGUI_API void UpdateClipRect(); IMGUI_API void UpdateTextureID(); }; @@ -1325,7 +1325,7 @@ struct ImFont IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; - IMGUI_API void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawList* draw_list, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; }; //---- Include imgui_user.h at the end of imgui.h diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2c421556..1dab652e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -918,14 +918,6 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. - // reserve vertices for worse case (over-reserving is useful and easily amortized) - const int char_count = (int)(text_end - text_begin); - const int vtx_count_max = char_count * 4; - const int idx_count_max = char_count * 6; - const int vtx_begin = VtxBuffer.Size; - const int idx_begin = IdxBuffer.Size; - PrimReserve(idx_count_max, vtx_count_max); - ImVec4 clip_rect = _ClipRectStack.back(); if (cpu_fine_clip_rect) { @@ -934,18 +926,7 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); } - font->RenderText(font_size, pos, col, clip_rect, text_begin, text_end, this, wrap_width, cpu_fine_clip_rect != NULL); - - // give back unused vertices - // FIXME-OPT: clean this up - VtxBuffer.resize((int)(_VtxWritePtr - VtxBuffer.Data)); - IdxBuffer.resize((int)(_IdxWritePtr - IdxBuffer.Data)); - int vtx_unused = vtx_count_max - (VtxBuffer.Size - vtx_begin); - int idx_unused = idx_count_max - (IdxBuffer.Size - idx_begin); - CmdBuffer.back().ElemCount -= idx_unused; - _VtxWritePtr -= vtx_unused; - _IdxWritePtr -= idx_unused; - _VtxCurrentIdx = (unsigned int)VtxBuffer.Size; + font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); } void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) @@ -1956,7 +1937,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col } } -void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawList* draw_list, float wrap_width, bool cpu_fine_clip) const +void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const { if (!text_end) text_end = text_begin + strlen(text_begin); @@ -1974,14 +1955,22 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re const bool word_wrap_enabled = (wrap_width > 0.0f); const char* word_wrap_eol = NULL; - ImDrawVert* vtx_write = draw_list->_VtxWritePtr; - ImDrawIdx* idx_write = draw_list->_IdxWritePtr; - unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; - + // Skip non-visible lines const char* s = text_begin; if (!word_wrap_enabled && y + line_height < clip_rect.y) while (s < text_end && *s != '\n') // Fast-forward to next line s++; + + // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) + const int vtx_count_max = (int)(text_end - s) * 4; + const int idx_count_max = (int)(text_end - s) * 6; + const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; + draw_list->PrimReserve(idx_count_max, vtx_count_max); + + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + while (s < text_end) { if (word_wrap_enabled) @@ -2050,11 +2039,10 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re if (c != ' ' && c != '\t') { // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w - float y1 = y + glyph->Y0 * scale; - float y2 = y + glyph->Y1 * scale; - float x1 = x + glyph->X0 * scale; float x2 = x + glyph->X1 * scale; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; if (x1 <= clip_rect.z && x2 >= clip_rect.x) { // Render a character @@ -2113,9 +2101,13 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re x += char_width; } + // Give back unused vertices + draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data)); + draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data)); + draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); draw_list->_VtxWritePtr = vtx_write; - draw_list->_VtxCurrentIdx = vtx_current_idx; draw_list->_IdxWritePtr = idx_write; + draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size; } //----------------------------------------------------------------------------- From a20d69f9ce4b074095a55b891de2e3be4af36a2e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 Apr 2016 11:29:42 +0200 Subject: [PATCH 097/400] ImFont: Tweaking layout, shaving bit of alignment and simple hot/cot split --- imgui.h | 31 ++++++++++++++++--------------- imgui_draw.cpp | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/imgui.h b/imgui.h index 0389269c..b6620490 100644 --- a/imgui.h +++ b/imgui.h @@ -1286,15 +1286,6 @@ struct ImFontAtlas // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). struct ImFont { - // Members: Settings - float FontSize; // // Height of characters, set during loading (don't change after loading) - float Scale; // = 1.0f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() - ImVec2 DisplayOffset; // = (0.0f,1.0f) // Offset font rendering by xx pixels - ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() - ImFontConfig* ConfigData; // // Pointer within ImFontAtlas->ConfigData - int ConfigDataCount; // - - // Members: Runtime data struct Glyph { ImWchar Codepoint; @@ -1302,13 +1293,23 @@ struct ImFont float X0, Y0, X1, Y1; float U0, V0, U1, V1; // Texture coordinates }; - float Ascent, Descent; // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] - ImFontAtlas* ContainerAtlas; // What we has been loaded into - ImVector Glyphs; + + // Members: Hot ~62/78 bytes + float FontSize; // // Height of characters, set during loading (don't change after loading) + float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() + ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels + ImVector Glyphs; // // All glyphs. + ImVector IndexXAdvance; // // Sparse. Glyphs->XAdvance in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). + ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) - float FallbackXAdvance; // - ImVector IndexXAdvance; // Sparse. Glyphs->XAdvance directly indexable (more cache-friendly that reading from Glyphs, for CalcTextSize functions which are often bottleneck in large UI) - ImVector IndexLookup; // Sparse. Index glyphs by Unicode code-point. + float FallbackXAdvance; // == FallbackGlyph->XAdvance + ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() + + // Members: Cold ~18/26 bytes + short ConfigDataCount; // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImFontConfig* ConfigData; // // Pointer within ContainerAtlas->ConfigData + ImFontAtlas* ContainerAtlas; // // What we has been loaded into + float Ascent, Descent; // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1dab652e..c3aec55d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1725,7 +1725,7 @@ const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const { const int i = IndexLookup[c]; if (i != -1) - return &Glyphs[i]; + return &Glyphs.Data[i]; } return FallbackGlyph; } From 727ca4bd17da6c07bf375e336062574cf1751f19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 Apr 2016 11:37:18 +0200 Subject: [PATCH 098/400] ImFont: IndexLookup stores short instead of int, so typical ascii-set lookup fits in 256 bytes --- imgui.h | 2 +- imgui_draw.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index b6620490..9e443189 100644 --- a/imgui.h +++ b/imgui.h @@ -1300,7 +1300,7 @@ struct ImFont ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels ImVector Glyphs; // // All glyphs. ImVector IndexXAdvance; // // Sparse. Glyphs->XAdvance in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). - ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. + ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) float FallbackXAdvance; // == FallbackGlyph->XAdvance ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c3aec55d..1afa8d2b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1675,6 +1675,7 @@ void ImFont::BuildLookupTable() for (int i = 0; i != Glyphs.Size; i++) max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + IM_ASSERT(Glyphs.Size < 32*1024); IndexXAdvance.clear(); IndexXAdvance.resize(max_codepoint + 1); IndexLookup.clear(); @@ -1682,13 +1683,13 @@ void ImFont::BuildLookupTable() for (int i = 0; i < max_codepoint + 1; i++) { IndexXAdvance[i] = -1.0f; - IndexLookup[i] = -1; + IndexLookup[i] = (short)-1; } for (int i = 0; i < Glyphs.Size; i++) { int codepoint = (int)Glyphs[i].Codepoint; IndexXAdvance[codepoint] = Glyphs[i].XAdvance; - IndexLookup[codepoint] = i; + IndexLookup[codepoint] = (short)i; } // Create a glyph to handle TAB @@ -1702,7 +1703,7 @@ void ImFont::BuildLookupTable() tab_glyph.Codepoint = '\t'; tab_glyph.XAdvance *= 4; IndexXAdvance[(int)tab_glyph.Codepoint] = (float)tab_glyph.XAdvance; - IndexLookup[(int)tab_glyph.Codepoint] = (int)(Glyphs.Size-1); + IndexLookup[(int)tab_glyph.Codepoint] = (short)(Glyphs.Size-1); } FallbackGlyph = NULL; @@ -1723,7 +1724,7 @@ const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const { if (c < IndexLookup.Size) { - const int i = IndexLookup[c]; + const short i = IndexLookup[c]; if (i != -1) return &Glyphs.Data[i]; } From 41215534d575e0166c09bdd75c19884c80d3c954 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 Apr 2016 14:10:36 +0200 Subject: [PATCH 099/400] Internal ImRound() -> ImFloor(), ImRect::Round() -> ImRect::Floor(), --- imgui.cpp | 6 +++--- imgui_internal.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4944a288..2ea7c257 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3376,7 +3376,7 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; const ImVec2 content_avail = ImGui::GetContentRegionAvail(); - ImVec2 size = ImRound(size_arg); + ImVec2 size = ImFloor(size_arg); if (size.x <= 0.0f) { if (size.x == 0.0f) @@ -9351,8 +9351,8 @@ void ImGui::ShowMetricsWindow(bool* opened) ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); - clip_rect.Round(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, ImColor(255,255,0)); - vtxs_rect.Round(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, ImColor(255,0,255)); + clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, ImColor(255,255,0)); + vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, ImColor(255,0,255)); } if (!draw_opened) continue; diff --git a/imgui_internal.h b/imgui_internal.h index c105a485..8d18d1b5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -135,7 +135,7 @@ static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } -static inline ImVec2 ImRound(ImVec2 v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } +static inline ImVec2 ImFloor(ImVec2 v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. // Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. @@ -231,7 +231,7 @@ struct IMGUI_API ImRect void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } void Reduce(const ImVec2& amount) { Min.x += amount.x; Min.y += amount.y; Max.x -= amount.x; Max.y -= amount.y; } void Clip(const ImRect& clip) { if (Min.x < clip.Min.x) Min.x = clip.Min.x; if (Min.y < clip.Min.y) Min.y = clip.Min.y; if (Max.x > clip.Max.x) Max.x = clip.Max.x; if (Max.y > clip.Max.y) Max.y = clip.Max.y; } - void Round() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } + void Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const { if (!on_edge && Contains(p)) From 1884f550bcf11371cdddf1fa374797ef4d305f1e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 Apr 2016 14:22:41 +0200 Subject: [PATCH 100/400] Fixed clipping rectangle floating point representation to ensure renderer-side ops yield correct results (#582, 597) --- imgui.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2ea7c257..563a1a6c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2372,13 +2372,14 @@ void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_ma ImGuiWindow* window = GetCurrentWindow(); ImRect cr(clip_rect_min, clip_rect_max); - if (intersect_with_existing_clip_rect) - { - // Clip our argument with the current clip rect + if (intersect_with_existing_clip_rect) // Clip our argument with the current clip rect cr.Clip(window->ClipRect); - } cr.Max.x = ImMax(cr.Min.x, cr.Max.x); cr.Max.y = ImMax(cr.Min.y, cr.Max.y); + cr.Min.x = (float)(int)(cr.Min.x + 0.5f); // Round (expecting to round down). Ensure that e.g. (int)(max.x-min.x) in user code produce correct result. + cr.Min.y = (float)(int)(cr.Min.y + 0.5f); + cr.Max.x = (float)(int)(cr.Max.x + 0.5f); + cr.Max.y = (float)(int)(cr.Max.y + 0.5f); IM_ASSERT(cr.Min.x <= cr.Max.x && cr.Min.y <= cr.Max.y); window->ClipRect = cr; @@ -4127,10 +4128,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ const ImRect title_bar_rect = window->TitleBarRect(); const float border_size = window->BorderSize; ImRect clip_rect; - clip_rect.Min.x = title_bar_rect.Min.x + 0.5f + ImMax(border_size, window->WindowPadding.x*0.5f); - clip_rect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + 0.5f + border_size; - clip_rect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - ImMax(border_size, window->WindowPadding.x*0.5f); - clip_rect.Max.y = window->Pos.y + window->Size.y - border_size - window->ScrollbarSizes.y; + clip_rect.Min.x = title_bar_rect.Min.x + ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); + clip_rect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + border_size; + clip_rect.Max.x = window->Pos.x + window->Size.x + window->ScrollbarSizes.x - ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); + clip_rect.Max.y = window->Pos.y + window->Size.y + border_size - window->ScrollbarSizes.y; PushClipRect(clip_rect.Min, clip_rect.Max, true); // Clear 'accessed' flag last thing @@ -8431,7 +8432,7 @@ bool ImGui::BeginMenuBar() ImGui::BeginGroup(); // Save position ImGui::PushID("##menubar"); ImRect rect = window->MenuBarRect(); - PushClipRect(ImVec2(rect.Min.x+0.5f, rect.Min.y-0.5f+window->BorderSize), ImVec2(rect.Max.x+0.5f, rect.Max.y-0.5f), false); + PushClipRect(ImVec2(rect.Min.x, rect.Min.y + window->BorderSize), ImVec2(rect.Max.x, rect.Max.y), false); window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.MenuBarAppending = true; From a0c411ffd2b8c91466abd33b10ba4cb62659c4c7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 23 Apr 2016 14:40:43 +0200 Subject: [PATCH 101/400] Fixed typos in previous commit 1884f550bcf11371cdddf1fa374797ef4d305f1e (#582, #597)) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 563a1a6c..700f4e49 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4130,8 +4130,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ ImRect clip_rect; clip_rect.Min.x = title_bar_rect.Min.x + ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); clip_rect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + border_size; - clip_rect.Max.x = window->Pos.x + window->Size.x + window->ScrollbarSizes.x - ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); - clip_rect.Max.y = window->Pos.y + window->Size.y + border_size - window->ScrollbarSizes.y; + clip_rect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); + clip_rect.Max.y = window->Pos.y + window->Size.y - border_size - window->ScrollbarSizes.y; PushClipRect(clip_rect.Min, clip_rect.Max, true); // Clear 'accessed' flag last thing From c2c0b57e5e18b3802fda4bda260e7592b738e434 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 Apr 2016 18:11:54 +0200 Subject: [PATCH 102/400] Examples: OpenGL2: Extra comments (#606) --- examples/opengl_example/imgui_impl_glfw.cpp | 4 ++++ examples/opengl_example/imgui_impl_glfw.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index fd9ce720..f6447e15 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -1,6 +1,10 @@ // ImGui GLFW binding with OpenGL // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. +// If your context is GL3/GL3 then prefer using the code in opengl3_example. +// You *might* use this code with a GL3/GL4 context but make sure you disable the programmable pipeline by calling "glUseProgram(0)" before ImGui::Render(). +// We cannot do that from GL2 code because the function doesn't exist. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl_example/imgui_impl_glfw.h index 09778224..07dd96f0 100644 --- a/examples/opengl_example/imgui_impl_glfw.h +++ b/examples/opengl_example/imgui_impl_glfw.h @@ -1,6 +1,10 @@ // ImGui GLFW binding with OpenGL // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. +// If your context is GL3/GL3 then prefer using the code in opengl3_example. +// You *might* use this code with a GL3/GL4 context but make sure you disable the programmable pipeline by calling "glUseProgram(0)" before ImGui::Render(). +// We cannot do that from GL2 code because the function doesn't exist. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. From a753aff07ae4b66e45277640be137a8bfcdd28e3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 Apr 2016 19:38:37 +0200 Subject: [PATCH 103/400] Moved Bullet*() code below TreeNode*() code. --- imgui.cpp | 118 +++++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 700f4e49..67a70bd4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5726,65 +5726,6 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display return opened; } -void ImGui::Bullet() -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return; - - ImGuiState& g = *GImGui; - const ImGuiStyle& style = g.Style; - const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); - const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); - ItemSize(bb); - if (!ItemAdd(bb, NULL)) - { - ImGui::SameLine(0, style.FramePadding.x*2); - return; - } - - // Render - const float bullet_size = g.FontSize*0.15f; - window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text)); - - // Stay on same line - ImGui::SameLine(0, style.FramePadding.x*2); -} - -// Text with a little bullet aligned to the typical tree node. -void ImGui::BulletTextV(const char* fmt, va_list args) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return; - - ImGuiState& g = *GImGui; - const ImGuiStyle& style = g.Style; - - const char* text_begin = g.TempBuffer; - const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - const ImVec2 label_size = CalcTextSize(text_begin, text_end, true); - const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it - const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); - const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding - ItemSize(bb); - if (!ItemAdd(bb, NULL)) - return; - - // Render - const float bullet_size = g.FontSize*0.15f; - window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text)); - RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end); -} - -void ImGui::BulletText(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - BulletTextV(fmt, args); - va_end(args); -} - // If returning 'true' the node is open and the user is responsible for calling TreePop bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) { @@ -5906,6 +5847,65 @@ ImGuiID ImGui::GetID(const void* ptr_id) return GImGui->CurrentWindow->GetID(ptr_id); } +void ImGui::Bullet() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiState& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); + ItemSize(bb); + if (!ItemAdd(bb, NULL)) + { + ImGui::SameLine(0, style.FramePadding.x*2); + return; + } + + // Render + const float bullet_size = g.FontSize*0.15f; + window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text)); + + // Stay on same line + ImGui::SameLine(0, style.FramePadding.x*2); +} + +// Text with a little bullet aligned to the typical tree node. +void ImGui::BulletTextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiState& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const char* text_begin = g.TempBuffer; + const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const ImVec2 label_size = CalcTextSize(text_begin, text_end, true); + const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it + const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding + ItemSize(bb); + if (!ItemAdd(bb, NULL)) + return; + + // Render + const float bullet_size = g.FontSize*0.15f; + window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text)); + RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end); +} + +void ImGui::BulletText(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + BulletTextV(fmt, args); + va_end(args); +} + static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size) { if (data_type == ImGuiDataType_Int) From 7da2d514801d131588b0ec2d10e66bd9ca402672 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 Apr 2016 22:36:46 +0200 Subject: [PATCH 104/400] MenuBar fixed missing lower border --- imgui.cpp | 4 +++- imgui_demo.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 67a70bd4..f7f92c0e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4016,6 +4016,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ { ImRect menu_bar_rect = window->MenuBarRect(); window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, 1|2); + if (flags & ImGuiWindowFlags_ShowBorders) + window->DrawList->AddLine(menu_bar_rect.GetBL()-ImVec2(0,0), menu_bar_rect.GetBR()-ImVec2(0,0), GetColorU32(ImGuiCol_Border)); } // Scrollbars @@ -4203,7 +4205,7 @@ static void Scrollbar(ImGuiWindow* window, bool horizontal) ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size) : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); if (!horizontal) - bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() - border_size : 0.0f); + bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; int window_rounding_corners; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 146df300..3a916252 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -268,7 +268,7 @@ void ImGui::ShowTestWindow(bool* p_opened) if (ImGui::CollapsingHeader("Widgets")) { - if (ImGui::TreeNode("Tree")) + if (ImGui::TreeNode("Trees")) { for (int i = 0; i < 5; i++) { @@ -412,7 +412,7 @@ void ImGui::ShowTestWindow(bool* p_opened) for (int i = 0; i < 16; i++) { ImGui::PushID(i); - if (ImGui::Selectable("Me", &selected[i], 0, ImVec2(50,50))) + if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50))) { int x = i % 4, y = i / 4; if (x > 0) selected[i - 1] ^= 1; From 919eb69931000e0a6426637862201e75671b223d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 Apr 2016 22:38:30 +0200 Subject: [PATCH 105/400] Scrollbar: minor fix for top-right rounding of scrollbar background when window has menubar but no title bar --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f7f92c0e..8da9c877 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4212,7 +4212,7 @@ static void Scrollbar(ImGuiWindow* window, bool horizontal) if (horizontal) window_rounding_corners = 8 | (other_scrollbar ? 0 : 4); else - window_rounding_corners = ((window->Flags & ImGuiWindowFlags_NoTitleBar) ? 2 : 0) | (other_scrollbar ? 0 : 4); + window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? 2 : 0) | (other_scrollbar ? 0 : 4); window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_ScrollbarBg), window_rounding, window_rounding_corners); bb.Reduce(ImVec2(ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f))); From 4b51e43d6064262190bea0a789deded55d2093a6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 24 Apr 2016 22:52:07 +0200 Subject: [PATCH 106/400] BeginGroup() extra comment because this is overused and misleading (#608) --- imgui.cpp | 2 +- imgui.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8da9c877..70f21615 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8813,6 +8813,7 @@ bool ImGui::IsRectVisible(const ImVec2& size) return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } +// Lock horizontal starting position + EndGroup() wraps group bounding box into one "item" (so you can use IsItemHovered() on a group, SameLine() between groups, etc.) void ImGui::BeginGroup() { ImGuiWindow* window = GetCurrentWindow(); @@ -9056,7 +9057,6 @@ void ImGui::Columns(int columns_count, const char* id, bool border) { if (g.ActiveIdIsJustActivated) g.ActiveClickDeltaToCenter.x = x - g.IO.MousePos.x; - x = GetDraggedColumnOffset(i); SetColumnOffset(i, x); } diff --git a/imgui.h b/imgui.h index 9e443189..c379c29e 100644 --- a/imgui.h +++ b/imgui.h @@ -187,14 +187,14 @@ namespace ImGui IMGUI_API void PopButtonRepeat(); // Cursor / Layout - IMGUI_API void BeginGroup(); // lock horizontal starting position. once closing a group it is seen as a single item (so you can use IsItemHovered() on a group, SameLine() between groups, etc. - IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally IMGUI_API void Spacing(); // add spacing IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) + IMGUI_API void BeginGroup(); // lock horizontal starting position + EndGroup() wraps group bounding box into one "item" (so you can use IsItemHovered() on a group, SameLine() between groups, etc.) + IMGUI_API void EndGroup(); IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position IMGUI_API float GetCursorPosX(); // " IMGUI_API float GetCursorPosY(); // " From 247da0e01be77a6ee8d7965d019ad13d1835b964 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 Apr 2016 08:45:32 +0200 Subject: [PATCH 107/400] BeginGroup() comment tweaks (#608) --- imgui.cpp | 2 +- imgui.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 70f21615..1d955c6e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8813,7 +8813,7 @@ bool ImGui::IsRectVisible(const ImVec2& size) return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } -// Lock horizontal starting position + EndGroup() wraps group bounding box into one "item" (so you can use IsItemHovered() on a group, SameLine() between groups, etc.) +// 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() { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui.h b/imgui.h index c379c29e..1f00795b 100644 --- a/imgui.h +++ b/imgui.h @@ -193,7 +193,7 @@ namespace ImGui IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) - IMGUI_API void BeginGroup(); // lock horizontal starting position + EndGroup() wraps group bounding box into one "item" (so you can use IsItemHovered() on a group, SameLine() between groups, etc.) + IMGUI_API void BeginGroup(); // lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) IMGUI_API void EndGroup(); IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position IMGUI_API float GetCursorPosX(); // " From 4b6e9ac396559815f5696428555b312f6412571a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Apr 2016 10:08:06 +0200 Subject: [PATCH 108/400] ImFont: Added AddRemapChar() helper (#609) --- imgui.cpp | 2 +- imgui.h | 10 +++++++--- imgui_draw.cpp | 38 +++++++++++++++++++++++++++++++------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1d955c6e..851135a9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -537,7 +537,7 @@ - style: WindowPadding needs to be EVEN needs the 0.5 multiplier probably have a subtle effect on clip rectangle - text: simple markup language for color change? - font: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier. - - font: helper to add glyph redirect/replacements (e.g. redirect alternate apostrophe unicode code points to ascii one, etc.) + - font: fix AddRemapChar() to work before font has been built. - log: LogButtons() options for specifying depth and/or hiding depth slider - log: have more control over the log scope (e.g. stop logging when leaving current tree node scope) - log: be able to log anything (e.g. right-click on a window/tree-node, shows context menu? log into tty/file/clipboard) diff --git a/imgui.h b/imgui.h index 1f00795b..05932e84 100644 --- a/imgui.h +++ b/imgui.h @@ -1316,10 +1316,10 @@ struct ImFont IMGUI_API ~ImFont(); IMGUI_API void Clear(); IMGUI_API void BuildLookupTable(); - IMGUI_API const Glyph* FindGlyph(unsigned short c) const; + IMGUI_API const Glyph* FindGlyph(ImWchar c) const; IMGUI_API void SetFallbackChar(ImWchar c); - float GetCharAdvance(unsigned short c) const { return ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] : FallbackXAdvance; } - bool IsLoaded() const { return ContainerAtlas != NULL; } + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] : FallbackXAdvance; } + bool IsLoaded() const { return ContainerAtlas != NULL; } // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. @@ -1327,6 +1327,10 @@ struct ImFont IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + + // Private + IMGUI_API void GrowIndex(int new_size); + IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. }; //---- Include imgui_user.h at the end of imgui.h diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1afa8d2b..b82b5cc9 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1677,14 +1677,8 @@ void ImFont::BuildLookupTable() IM_ASSERT(Glyphs.Size < 32*1024); IndexXAdvance.clear(); - IndexXAdvance.resize(max_codepoint + 1); IndexLookup.clear(); - IndexLookup.resize(max_codepoint + 1); - for (int i = 0; i < max_codepoint + 1; i++) - { - IndexXAdvance[i] = -1.0f; - IndexLookup[i] = (short)-1; - } + GrowIndex(max_codepoint + 1); for (int i = 0; i < Glyphs.Size; i++) { int codepoint = (int)Glyphs[i].Codepoint; @@ -1720,6 +1714,36 @@ void ImFont::SetFallbackChar(ImWchar c) BuildLookupTable(); } +void ImFont::GrowIndex(int new_size) +{ + IM_ASSERT(IndexXAdvance.Size == IndexLookup.Size); + int old_size = IndexLookup.Size; + if (new_size <= old_size) + return; + IndexXAdvance.resize(new_size); + IndexLookup.resize(new_size); + for (int i = old_size; i < new_size; i++) + { + IndexXAdvance[i] = -1.0f; + IndexLookup[i] = (short)-1; + } +} + +void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) +{ + IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. + int index_size = IndexLookup.Size; + + if (dst < index_size && IndexLookup.Data[dst] == -1 && !overwrite_dst) // 'dst' already exists + return; + if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op + return; + + GrowIndex(dst + 1); + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : -1; + IndexXAdvance[dst] = (src < index_size) ? IndexXAdvance.Data[src] : 1.0f; +} + const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const { if (c < IndexLookup.Size) From ea6b6151791c77c70c364f871c9e076b76739e09 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Apr 2016 11:03:51 +0200 Subject: [PATCH 109/400] Made ImGui::PushClipRect()/PopClipRect() public. Changed ImDrawList::PushClipRect() prototype. Fixed demo. (#610) --- imgui.cpp | 20 ++++---------------- imgui.h | 6 +++++- imgui_demo.cpp | 2 +- imgui_draw.cpp | 29 +++++++++++++++++++++-------- imgui_internal.h | 3 --- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 851135a9..ad3c6c11 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -152,6 +152,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). @@ -557,7 +558,6 @@ - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438) - style editor: color child window height expressed in multiple of line height. - remote: make a system like RemoteImGui first-class citizen/project (#75) -!- demo: custom render demo pushes a clipping rectangle past parent window bounds. expose ImGui::PushClipRect() from imgui_internal.h? - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - examples: directx9: save/restore device state more thoroughly. - examples: window minimize, maximize (#583) @@ -2367,23 +2367,11 @@ static void AddWindowToRenderList(ImVector& out_render_list, ImGuiW } } -void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_existing_clip_rect) +void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); - - ImRect cr(clip_rect_min, clip_rect_max); - if (intersect_with_existing_clip_rect) // Clip our argument with the current clip rect - cr.Clip(window->ClipRect); - cr.Max.x = ImMax(cr.Min.x, cr.Max.x); - cr.Max.y = ImMax(cr.Min.y, cr.Max.y); - cr.Min.x = (float)(int)(cr.Min.x + 0.5f); // Round (expecting to round down). Ensure that e.g. (int)(max.x-min.x) in user code produce correct result. - cr.Min.y = (float)(int)(cr.Min.y + 0.5f); - cr.Max.x = (float)(int)(cr.Max.x + 0.5f); - cr.Max.y = (float)(int)(cr.Max.y + 0.5f); - - IM_ASSERT(cr.Min.x <= cr.Max.x && cr.Min.y <= cr.Max.y); - window->ClipRect = cr; - window->DrawList->PushClipRect(ImVec4(cr.Min.x, cr.Min.y, cr.Max.x, cr.Max.y)); + window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); + window->ClipRect = window->DrawList->_ClipRectStack.back(); } void ImGui::PopClipRect() diff --git a/imgui.h b/imgui.h index 05932e84..d6a097ee 100644 --- a/imgui.h +++ b/imgui.h @@ -368,6 +368,10 @@ namespace ImGui IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard IMGUI_API void LogText(const char* fmt, ...) IM_PRINTFARGS(1); // pass text data straight to log (without being displayed) + // Clipping + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); + IMGUI_API void PopClipRect(); + // Utilities IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? IMGUI_API bool IsItemHoveredRect(); // was the last item hovered by mouse? even if another item is active or window is blocked by popup while we are hovering this @@ -1128,7 +1132,7 @@ struct ImDrawList ImDrawList() { _OwnerName = NULL; Clear(); } ~ImDrawList() { ClearFreeMemory(); } - IMGUI_API void PushClipRect(const ImVec4& clip_rect); // Scissoring. Note that the values are (x1,y1,x2,y2) and NOT (x1,y1,w,h). This is passed down to your render function but not used for CPU-side clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) + IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) IMGUI_API void PushClipRectFullScreen(); IMGUI_API void PopClipRect(); IMGUI_API void PushTextureID(const ImTextureID& texture_id); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3a916252..cf6cf21b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1863,7 +1863,7 @@ static void ShowExampleAppCustomRendering(bool* opened) points.pop_back(); } } - draw_list->PushClipRect(ImVec4(canvas_pos.x, canvas_pos.y, canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y)); // clip lines within the canvas (if we resize it, etc.) + draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y)); // clip lines within the canvas (if we resize it, etc.) for (int i = 0; i < points.Size - 1; i += 2) draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i+1].x, canvas_pos.y + points[i+1].y), 0xFF00FFFF, 2.0f); draw_list->PopClipRect(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b82b5cc9..e2eea92c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -214,20 +214,33 @@ void ImDrawList::UpdateTextureID() #undef GetCurrentClipRect #undef GetCurrentTextureId -// Scissoring. The values in clip_rect are x1, y1, x2, y2. Only apply to rendering! Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) -void ImDrawList::PushClipRect(const ImVec4& clip_rect) +// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) +void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) { - _ClipRectStack.push_back(clip_rect); + ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); + if (intersect_with_current_clip_rect && _ClipRectStack.Size) + { + ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1]; + if (cr.x < current.x) cr.x = current.x; + if (cr.y < current.y) cr.y = current.y; + if (cr.z > current.z) cr.z = current.z; + if (cr.w > current.w) cr.w = current.w; + } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); + cr.x = (float)(int)(cr.x + 0.5f); // Round (expecting to round down). Ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + cr.y = (float)(int)(cr.y + 0.5f); + cr.z = (float)(int)(cr.z + 0.5f); + cr.w = (float)(int)(cr.w + 0.5f); + + _ClipRectStack.push_back(cr); UpdateClipRect(); } void ImDrawList::PushClipRectFullScreen() { - PushClipRect(GNullClipRect); - - // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiState from here? - //ImGuiState& g = *GImGui; - //PushClipRect(GetVisibleRect()); + PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w)); + //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiState from here? } void ImDrawList::PopClipRect() diff --git a/imgui_internal.h b/imgui_internal.h index 8d18d1b5..90ceba1a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -711,9 +711,6 @@ namespace ImGui IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. - IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_existing_clip_rect = true); - IMGUI_API void PopClipRect(); - IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); From 544ba36bf66e877b4ce69eb03a9d93736e6dab24 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Apr 2016 11:59:56 +0200 Subject: [PATCH 110/400] Fixed GetFrontMostModalRootWindow() (#604) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ad3c6c11..c3184d3f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3210,8 +3210,8 @@ static void CloseInactivePopups() static ImGuiWindow* GetFrontMostModalRootWindow() { ImGuiState& g = *GImGui; - if (!g.OpenedPopupStack.empty()) - if (ImGuiWindow* front_most_popup = g.OpenedPopupStack.back().Window) + for (int n = g.OpenedPopupStack.Size-1; n >= 0; n--) + if (ImGuiWindow* front_most_popup = g.OpenedPopupStack.Data[n].Window) if (front_most_popup->Flags & ImGuiWindowFlags_Modal) return front_most_popup; return NULL; From be7621f7c55bb4f410f6a545efd62babb10c5649 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 26 Apr 2016 19:23:36 +0200 Subject: [PATCH 111/400] Updated FAQ about non UTF-8 literal (#609, #613) --- imgui.cpp | 8 ++++++-- imgui.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c3184d3f..8fb4a18f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -411,13 +411,17 @@ io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? - A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. ImGui will support UTF-8 encoding across the board. - Character input depends on you passing the right character code to io.AddInputCharacter(). The example applications do that. + A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. + All strings passed need to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will not work. + In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. + You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code. io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() io.ImeWindowHandle = MY_HWND; // To input using Microsoft IME, give ImGui the hwnd of your application + As for text input, depends on you passing the right character code to io.AddInputCharacter(). The example applications do that. + - tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code. - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug" - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of another window (to get/set other settings) diff --git a/imgui.h b/imgui.h index d6a097ee..e093116e 100644 --- a/imgui.h +++ b/imgui.h @@ -1262,7 +1262,7 @@ struct ImFontAtlas void SetTexID(void* id) { TexID = id; } // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) - // (Those functions could be static but aren't so most users don't have to refer to the ImFontAtlas:: name ever if in their code; just using io.Fonts->) + // NB: Make sure that your string are UTF-8 and NOT in your local code page. See FAQ for details. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs From c5149cd53c80d022e6924b20e964544e9537cb20 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Apr 2016 23:34:24 +0200 Subject: [PATCH 112/400] MenuItem(): checkmark render in disabled color when disabled --- imgui.cpp | 4 ++-- imgui_internal.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8fb4a18f..1010afb7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8364,7 +8364,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame float extra_w = ImMax(0.0f, ImGui::GetContentRegionAvail().x - w); - bool pressed = ImGui::Selectable(label, false, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + bool pressed = ImGui::Selectable(label, false, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DrawFillAvailWidth | (enabled ? 0 : ImGuiSelectableFlags_Disabled), ImVec2(w, 0.0f)); if (shortcut_size.x > 0.0f) { ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); @@ -8373,7 +8373,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo } if (selected) - RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), GetColorU32(ImGuiCol_Text)); + RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled)); return pressed; } diff --git a/imgui_internal.h b/imgui_internal.h index 90ceba1a..eff7e27b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -707,7 +707,7 @@ namespace ImGui IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); - IMGUI_API void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); + IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool opened, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. From 819cc414b1014d685e39bb32b5c2b65c72c4ecfa Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 Apr 2016 10:25:23 +0200 Subject: [PATCH 113/400] Metrics window: uses IM_COL32() macro to generate constant colors. --- imgui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1010afb7..0038d011 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9346,8 +9346,8 @@ void ImGui::ShowMetricsWindow(bool* opened) ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); - clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, ImColor(255,255,0)); - vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, ImColor(255,0,255)); + clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255)); + vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255)); } if (!draw_opened) continue; @@ -9363,7 +9363,7 @@ void ImGui::ShowMetricsWindow(bool* opened) } ImGui::Selectable(buf, false); if (ImGui::IsItemHovered()) - overlay_draw_list->AddPolyline(triangles_pos, 3, ImColor(255,255,0), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle + overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle } ImGui::TreePop(); } From 7406d64c64a2759fd82ea7dad93b1e15a0615c85 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 30 Apr 2016 18:55:23 +0200 Subject: [PATCH 114/400] PushClipRect(): not altering passed values, leave it to caller responsibility to floor properly (followup #582) --- imgui.cpp | 20 +++++++++++--------- imgui_draw.cpp | 4 ---- imgui_internal.h | 1 + 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0038d011..77f63090 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -552,6 +552,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: tooltip & combo boxes are messing up / not honoring keyboard tabbing - keyboard: full keyboard navigation and focus. (#323) + - focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622) - focus: SetKeyboardFocusHere() on with >= 0 offset could be done on same frame (else latch and modulate on beginning of next frame) - input: rework IO system to be able to pass actual ordered/timestamped events. - input: allow to decide and pass explicit double-clicks (e.g. for windows by the CS_DBLCLKS style). @@ -2371,6 +2372,7 @@ static void AddWindowToRenderList(ImVector& out_render_list, ImGuiW } } +// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); @@ -4121,11 +4123,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. const ImRect title_bar_rect = window->TitleBarRect(); const float border_size = window->BorderSize; - ImRect clip_rect; - clip_rect.Min.x = title_bar_rect.Min.x + ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); - clip_rect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + border_size; - clip_rect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - ImMax(border_size, (float)(int)(window->WindowPadding.x*0.5f)); - clip_rect.Max.y = window->Pos.y + window->Size.y - border_size - window->ScrollbarSizes.y; + ImRect clip_rect; // Force round to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + clip_rect.Min.x = ImFloor(0.5f + title_bar_rect.Min.x + ImMax(border_size, ImFloor(window->WindowPadding.x*0.5f))); + clip_rect.Min.y = ImFloor(0.5f + title_bar_rect.Max.y + window->MenuBarHeight() + border_size); + clip_rect.Max.x = ImFloor(0.5f + window->Pos.x + window->Size.x - window->ScrollbarSizes.x - ImMax(border_size, ImFloor(window->WindowPadding.x*0.5f))); + clip_rect.Max.y = ImFloor(0.5f + window->Pos.y + window->Size.y - window->ScrollbarSizes.y - border_size); PushClipRect(clip_rect.Min, clip_rect.Max, true); // Clear 'accessed' flag last thing @@ -8426,7 +8428,7 @@ bool ImGui::BeginMenuBar() ImGui::BeginGroup(); // Save position ImGui::PushID("##menubar"); ImRect rect = window->MenuBarRect(); - PushClipRect(ImVec2(rect.Min.x, rect.Min.y + window->BorderSize), ImVec2(rect.Max.x, rect.Max.y), false); + PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->BorderSize + 0.5f)), ImVec2(ImFloor(rect.Max.x+0.5f), ImFloor(rect.Max.y+0.5f)), false); window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.MenuBarAppending = true; @@ -8989,7 +8991,7 @@ float ImGui::GetColumnWidth(int column_index) if (column_index < 0) column_index = window->DC.ColumnsCurrent; - const float w = GetColumnOffset(column_index+1) - GetColumnOffset(column_index); + float w = GetColumnOffset(column_index+1) - GetColumnOffset(column_index); return w; } @@ -8999,8 +9001,8 @@ static void PushColumnClipRect(int column_index) if (column_index < 0) column_index = window->DC.ColumnsCurrent; - const float x1 = window->Pos.x + ImGui::GetColumnOffset(column_index) - 1; - const float x2 = window->Pos.x + ImGui::GetColumnOffset(column_index+1) - 1; + float x1 = ImFloor(0.5f + window->Pos.x + ImGui::GetColumnOffset(column_index) - 1.0f); + float x2 = ImFloor(0.5f + window->Pos.x + ImGui::GetColumnOffset(column_index+1) - 1.0f); ImGui::PushClipRect(ImVec2(x1,-FLT_MAX), ImVec2(x2,+FLT_MAX), true); } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e2eea92c..da070b22 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -228,10 +228,6 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_ } cr.z = ImMax(cr.x, cr.z); cr.w = ImMax(cr.y, cr.w); - cr.x = (float)(int)(cr.x + 0.5f); // Round (expecting to round down). Ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. - cr.y = (float)(int)(cr.y + 0.5f); - cr.z = (float)(int)(cr.z + 0.5f); - cr.w = (float)(int)(cr.w + 0.5f); _ClipRectStack.push_back(cr); UpdateClipRect(); diff --git a/imgui_internal.h b/imgui_internal.h index eff7e27b..41fb04f9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -135,6 +135,7 @@ static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } +static inline float ImFloor(float f) { return (float)(int)f; } static inline ImVec2 ImFloor(ImVec2 v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. From bfb2dc22907f129a4a62c1ba3394ddecf00e57e5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 30 Apr 2016 19:02:19 +0200 Subject: [PATCH 115/400] Examples: OpenGL3: Saving/restoring glActiveTexture() state (#602) --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 2 ++ examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index b1d2a40b..0e3a754c 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -46,6 +46,7 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) // Backup GL state GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + GLint last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, &last_active_texture); GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); @@ -111,6 +112,7 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) // Restore modified GL state glUseProgram(last_program); + glActiveTexture(last_active_texture); glBindTexture(GL_TEXTURE_2D, last_texture); glBindVertexArray(last_vertex_array); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 5406f424..c3fed5f0 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -40,6 +40,7 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) // Backup GL state GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); + GLint last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, &last_active_texture); GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); @@ -105,6 +106,7 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) // Restore modified GL state glUseProgram(last_program); + glActiveTexture(last_active_texture); glBindTexture(GL_TEXTURE_2D, last_texture); glBindVertexArray(last_vertex_array); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); From 60d6c6d0e8cb88828758ebe81830ef478be17673 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 11:46:49 +0200 Subject: [PATCH 116/400] Comments/tweaks on ItemAdd() --- imgui.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 77f63090..c6c4f04a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1721,29 +1721,23 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) ImGuiWindow* window = GetCurrentWindow(); window->DC.LastItemID = id ? *id : 0; window->DC.LastItemRect = bb; + window->DC.LastItemHoveredAndUsable = false; + window->DC.LastItemHoveredRect = false; if (IsClippedEx(bb, id, false)) - { - window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; return false; - } // This is a sensible default, but widgets are free to override it after calling ItemAdd() ImGuiState& g = *GImGui; if (IsMouseHoveringRect(bb.Min, bb.Max)) { - // Matching the behavior of IsHovered() but ignore if ActiveId==window->MoveID (we clicked on the window background) + // Matching the behavior of IsHovered() but allow if ActiveId==window->MoveID (we clicked on the window background) // So that clicking on items with no active id such as Text() still returns true with IsItemHovered() window->DC.LastItemHoveredRect = true; - window->DC.LastItemHoveredAndUsable = false; if (g.HoveredRootWindow == window->RootWindow) if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdAllowOverlap || (g.ActiveId == window->MoveID)) if (IsWindowContentHoverable(window)) window->DC.LastItemHoveredAndUsable = true; } - else - { - window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; - } return true; } @@ -1754,14 +1748,13 @@ bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when ImGuiWindow* window = GetCurrentWindowRead(); if (!bb.Overlaps(window->ClipRect)) - { if (!id || *id != GImGui->ActiveId) if (clip_even_when_logged || !g.LogEnabled) return true; - } return false; } +// NB: This is an internal helper. The user-facing IsItemHovered() is using data emitted from ItemAdd(), with a slightly different logic. bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs) { ImGuiState& g = *GImGui; From befe02559ac3de15d1ba3a41d0939696cf6330a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 12:14:07 +0200 Subject: [PATCH 117/400] Added IsRootWindowOrAnyChildHovered() helper (#615) --- imgui.cpp | 12 ++++++++---- imgui.h | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c6c4f04a..d15f3b01 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4579,15 +4579,19 @@ bool ImGui::IsWindowFocused() bool ImGui::IsRootWindowFocused() { ImGuiState& g = *GImGui; - ImGuiWindow* root_window = g.CurrentWindow->RootWindow; - return g.FocusedWindow == root_window; + return g.FocusedWindow == g.CurrentWindow->RootWindow; } bool ImGui::IsRootWindowOrAnyChildFocused() { ImGuiState& g = *GImGui; - ImGuiWindow* root_window = g.CurrentWindow->RootWindow; - return g.FocusedWindow && g.FocusedWindow->RootWindow == root_window; + return g.FocusedWindow && g.FocusedWindow->RootWindow == g.CurrentWindow->RootWindow; +} + +bool ImGui::IsRootWindowOrAnyChildHovered() +{ + ImGuiState& g = *GImGui; + return g.HoveredRootWindow && (g.HoveredRootWindow == g.CurrentWindow->RootWindow) && IsWindowContentHoverable(g.HoveredRootWindow); } float ImGui::GetWindowWidth() diff --git a/imgui.h b/imgui.h index e093116e..a451cea7 100644 --- a/imgui.h +++ b/imgui.h @@ -385,8 +385,9 @@ namespace ImGui IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. IMGUI_API bool IsWindowHovered(); // is current window hovered and hoverable (not blocked by a popup) (differentiate child windows from each others) IMGUI_API bool IsWindowFocused(); // is current window focused - IMGUI_API bool IsRootWindowFocused(); // is current root window focused (top parent window in case of child windows) + IMGUI_API bool IsRootWindowFocused(); // is current root window focused (root = top-most parent of a child, otherwise self) IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused + IMGUI_API bool IsRootWindowOrAnyChildHovered(); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup) IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle of given size starting from cursor pos is visible (not clipped). to perform coarse clipping on user's side (as an optimization) IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API float GetTime(); From df749e3f1357edf924f584710591749095fbfe2b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 14:34:55 +0200 Subject: [PATCH 118/400] Added CollapsingHeader() variant with close button, obsoleted 4 parameters version. Refactored code into TreeNodeBehavior. (#600) New flag and declaration makes uses of SetNextTreeNode() functions on collapsing header more obvious as well (#579). --- imgui.cpp | 145 ++++++++++++++++++++++++++++------------------- imgui.h | 21 ++++++- imgui_demo.cpp | 17 ++++++ imgui_internal.h | 11 ++-- 4 files changed, 127 insertions(+), 67 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d15f3b01..f6b0742a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -152,6 +152,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) @@ -5260,7 +5261,15 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } bool pressed = false; - const bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0); + bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0); + + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. + if (hovered && (flags & ImGuiButtonFlags_AllowOverlapMode) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + { + SetHoveredID(id); + hovered = false; + } + if (hovered) { SetHoveredID(id); @@ -5626,14 +5635,13 @@ bool ImGui::TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags) // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). // NB- If we are above max depth we still allow manually opened nodes to be logged. - if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoExpandOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) + if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) opened = true; return opened; } -// FIXME: Split into CollapsingHeader(label, default_open?) and TreeNodeBehavior(label), obsolete the 4 parameters function. -bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display_frame, bool default_open) +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -5641,20 +5649,16 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; + const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; const ImVec2 padding = display_frame ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); - IM_ASSERT(str_id != NULL || label != NULL); - if (str_id == NULL) - str_id = label; - if (label == NULL) - label = str_id; - const bool label_hide_text_after_double_hash = (label == str_id); // Only search and hide text after ## if we have passed label and ID separately, otherwise allow "##" within format string. - const ImGuiID id = window->GetID(str_id); - const ImVec2 label_size = CalcTextSize(label, NULL, label_hide_text_after_double_hash); + if (!label_end) + label_end = FindRenderedTextEnd(label); + const ImVec2 label_size = CalcTextSize(label, label_end, false); // We vertically grow up to current line height up the typical widget height. const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset - padding.y); // Latch before ItemSize changes it - const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), label_size.y + padding.y*2); + const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); ImRect bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height)); if (display_frame) { @@ -5670,12 +5674,15 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing // (Ideally we'd want to add a flag for the user to specify we want want the hit test to be done up to the right side of the content or not) const ImRect interact_bb = display_frame ? bb : ImRect(bb.Min.x, bb.Min.y, bb.Min.x + text_width + style.ItemSpacing.x*2, bb.Max.y); - bool opened = TreeNodeBehaviorIsOpened(id, (default_open ? ImGuiTreeNodeFlags_DefaultOpen : 0) | (display_frame ? ImGuiTreeNodeFlags_NoAutoExpandOnLog : 0)); + bool opened = TreeNodeBehaviorIsOpened(id, flags); if (!ItemAdd(interact_bb, &id)) + { + if (opened && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushRawID(id); return opened; + } - bool hovered, held; - bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, ImGuiButtonFlags_NoKeyModifiers); + bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowOverlapMode : 0)); if (pressed) { opened = !opened; @@ -5696,12 +5703,12 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display const char log_prefix[] = "\n##"; const char log_suffix[] = "##"; LogRenderedText(text_pos, log_prefix, log_prefix+3); - RenderTextClipped(text_pos, bb.Max, label, NULL, &label_size); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); LogRenderedText(text_pos, log_suffix+1, log_suffix+3); } else { - RenderTextClipped(text_pos, bb.Max, label, NULL, &label_size); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); } } else @@ -5713,13 +5720,47 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); if (g.LogEnabled) LogRenderedText(text_pos, ">"); - RenderText(text_pos, label, NULL, label_hide_text_after_double_hash); + RenderText(text_pos, label, label_end, false); + } + + if (opened && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushRawID(id); + return opened; +} + +bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen, label); +} + +bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (p_open && !*p_open) + return false; + + ImGuiID id = window->GetID(label); + bool opened = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen | (p_open ? ImGuiTreeNodeFlags_AllowOverlapMode : 0), label); + if (p_open) + { + // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. + ImGuiState& g = *GImGui; + SetItemAllowOverlap(); + float button_sz = g.FontSize * 0.5f; + if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(window->DC.LastItemRect.Max.x - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz)) + *p_open = false; } return opened; } -// If returning 'true' the node is open and the user is responsible for calling TreePop bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) { ImGuiWindow* window = GetCurrentWindow(); @@ -5727,30 +5768,10 @@ bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) return false; ImGuiState& g = *GImGui; - ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - if (!str_id || !str_id[0]) - str_id = fmt; - - ImGui::PushID(str_id); - const bool opened = ImGui::CollapsingHeader(g.TempBuffer, "", false); - ImGui::PopID(); - - if (opened) - ImGui::TreePush(str_id); - - return opened; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(str_id), 0, g.TempBuffer, label_end); } -bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - bool s = TreeNodeV(str_id, fmt, args); - va_end(args); - return s; -} - -// If returning 'true' the node is open and the user is responsible for calling TreePop bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) { ImGuiWindow* window = GetCurrentWindow(); @@ -5758,18 +5779,16 @@ bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) return false; ImGuiState& g = *GImGui; - ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - - if (!ptr_id) - ptr_id = fmt; - - ImGui::PushID(ptr_id); - const bool opened = ImGui::CollapsingHeader(g.TempBuffer, "", false); - ImGui::PopID(); - - if (opened) - ImGui::TreePush(ptr_id); + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id ? ptr_id : fmt), 0, g.TempBuffer, label_end); +} +bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool opened = TreeNodeV(str_id, fmt, args); + va_end(args); return opened; } @@ -5777,14 +5796,18 @@ bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) { va_list args; va_start(args, fmt); - bool s = TreeNodeV(ptr_id, fmt, args); + bool opened = TreeNodeV(ptr_id, fmt, args); va_end(args); - return s; + return opened; } -bool ImGui::TreeNode(const char* str_label_id) +bool ImGui::TreeNode(const char* label) { - return TreeNode(str_label_id, "%s", str_label_id); + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), 0, label, NULL); } void ImGui::SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond) @@ -9127,6 +9150,14 @@ void ImGui::TreePush(const void* ptr_id) PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); } +void ImGui::TreePushRawID(ImGuiID id) +{ + ImGuiWindow* window = GetCurrentWindow(); + ImGui::Indent(); + window->DC.TreeDepth++; + window->IDStack.push_back(id); +} + void ImGui::TreePop() { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui.h b/imgui.h index a451cea7..6a46035b 100644 --- a/imgui.h +++ b/imgui.h @@ -70,6 +70,7 @@ typedef int ImGuiWindowFlags; // window flags for Begin*() // e typedef int ImGuiSetCond; // condition flags for Set*() // enum ImGuiSetCond_ typedef int ImGuiInputTextFlags; // flags for InputText*() // enum ImGuiInputTextFlags_ typedef int ImGuiSelectableFlags; // flags for Selectable() // enum ImGuiSelectableFlags_ +typedef int ImGuiTreeNodeFlags; // flags for TreeNode*(), Collapsing*() // enum ImGuiTreeNodeFlags_ typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); // Others helpers at bottom of the file: @@ -251,7 +252,6 @@ namespace ImGui IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); 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 CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false); IMGUI_API bool Checkbox(const char* label, bool* v); IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool RadioButton(const char* label, bool active); @@ -307,15 +307,17 @@ namespace ImGui IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); // Widgets: Trees - IMGUI_API bool TreeNode(const char* str_label_id); // if returning 'true' the node is open and the user is responsible for calling TreePop(). + 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_PRINTFARGS(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(). IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_PRINTFARGS(2); // " IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args); // " IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args); // " - IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layouting purpose + IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layout purpose IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node/collapsing header to be opened. + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. user doesn't have to call TreePop(). + IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header // Widgets: Selectable / Lists IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height @@ -441,6 +443,7 @@ namespace ImGui // Obsolete (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + static inline bool CollapsingHeader(const char* label, const char* str_id, bool display_frame = true, bool default_open = false) { (void)str_id; (void)display_frame; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ @@ -512,6 +515,18 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() }; +// Flags for ImGui::TreeNode*(), ImGui::CollapsingHeader*() +enum ImGuiTreeNodeFlags_ +{ + ImGuiTreeNodeFlags_Selected = 1 << 0, + ImGuiTreeNodeFlags_Framed = 1 << 1, + ImGuiTreeNodeFlags_AllowOverlapMode = 1 << 2, + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog, +}; + // Flags for ImGui::Selectable() enum ImGuiSelectableFlags_ { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index cf6cf21b..ac88f842 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -284,6 +284,23 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::TreePop(); } + if (ImGui::TreeNode("Collapsing Headers")) + { + static bool closable_group = true; + if (ImGui::CollapsingHeader("Header")) + { + ImGui::Checkbox("Enable extra group", &closable_group); + for (int i = 0; i < 5; i++) + ImGui::Text("Some content %d", i); + } + if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) + { + for (int i = 0; i < 5; i++) + ImGui::Text("More content %d", i); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Bullets")) { ImGui::BulletText("Bullet point 1"); diff --git a/imgui_internal.h b/imgui_internal.h index 41fb04f9..d099d3b7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -161,13 +161,8 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_DontClosePopups = 1 << 5, // disable automatically closing parent popup on press ImGuiButtonFlags_Disabled = 1 << 6, // disable interaction ImGuiButtonFlags_AlignTextBaseLine = 1 << 7, // vertically align button to match text baseline - ButtonEx() only - ImGuiButtonFlags_NoKeyModifiers = 1 << 8 // disable interaction if a key modifier is held -}; - -enum ImGuiTreeNodeFlags_ -{ - ImGuiTreeNodeFlags_DefaultOpen = 1 << 0, - ImGuiTreeNodeFlags_NoAutoExpandOnLog = 1 << 1 + ImGuiButtonFlags_NoKeyModifiers = 1 << 8, // disable interaction if a key modifier is held + ImGuiButtonFlags_AllowOverlapMode = 1 << 9 // require previous frame HoveredId to either match id or be null before being usable }; enum ImGuiSliderFlags_ @@ -730,7 +725,9 @@ namespace ImGui IMGUI_API bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API bool TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging + IMGUI_API void TreePushRawID(ImGuiID id); IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); From ab6bc05fc34c9249393b85788b088c4bc20ded29 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 15:44:50 +0200 Subject: [PATCH 119/400] Fixed ImGuiTreeNodeFlags_AllowOverlapMode to behave better on touch-style inputs (#600) --- imgui.cpp | 15 ++++++--------- imgui.h | 14 +++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f6b0742a..47ecc56d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5262,14 +5262,6 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool bool pressed = false; bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0); - - // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (hovered && (flags & ImGuiButtonFlags_AllowOverlapMode) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) - { - SetHoveredID(id); - hovered = false; - } - if (hovered) { SetHoveredID(id); @@ -5319,6 +5311,10 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } } + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. + if (hovered && (flags & ImGuiButtonFlags_AllowOverlapMode) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + hovered = pressed = held = false; + if (out_hovered) *out_hovered = hovered; if (out_held) *out_held = held; @@ -5688,6 +5684,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l opened = !opened; window->DC.StateStorage->SetInt(id, opened); } + if (flags & ImGuiTreeNodeFlags_AllowOverlapMode) + SetItemAllowOverlap(); // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); @@ -5752,7 +5750,6 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags { // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. ImGuiState& g = *GImGui; - SetItemAllowOverlap(); float button_sz = g.FontSize * 0.5f; if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(window->DC.LastItemRect.Max.x - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz)) *p_open = false; diff --git a/imgui.h b/imgui.h index 6a46035b..953d1f65 100644 --- a/imgui.h +++ b/imgui.h @@ -518,13 +518,13 @@ enum ImGuiInputTextFlags_ // Flags for ImGui::TreeNode*(), ImGui::CollapsingHeader*() enum ImGuiTreeNodeFlags_ { - ImGuiTreeNodeFlags_Selected = 1 << 0, - ImGuiTreeNodeFlags_Framed = 1 << 1, - ImGuiTreeNodeFlags_AllowOverlapMode = 1 << 2, - ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, - ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, - ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, - ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog, + ImGuiTreeNodeFlags_Selected = 1 << 0, // FIXME: TODO + ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_AllowOverlapMode = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when opened (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes). + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be opened + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; // Flags for ImGui::Selectable() From ec6471ca87c64e70cbd984265eeedfdf2076d34b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 16:06:46 +0200 Subject: [PATCH 120/400] TreeNodeEx() wired the display-side ImGuiTreeNodeFlags_Selected flag (#581) --- imgui.cpp | 2 +- imgui.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 47ecc56d..7aff89cc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5712,7 +5712,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l else { // Unframed typed for tree nodes - if (hovered) + if (hovered || (flags & ImGuiTreeNodeFlags_Selected)) RenderFrame(bb.Min, bb.Max, col, false); RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); diff --git a/imgui.h b/imgui.h index 953d1f65..11b63b8f 100644 --- a/imgui.h +++ b/imgui.h @@ -518,7 +518,7 @@ enum ImGuiInputTextFlags_ // Flags for ImGui::TreeNode*(), ImGui::CollapsingHeader*() enum ImGuiTreeNodeFlags_ { - ImGuiTreeNodeFlags_Selected = 1 << 0, // FIXME: TODO + ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) ImGuiTreeNodeFlags_AllowOverlapMode = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when opened (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack From ac501102fc7524433c2343f2fa2cc47ea08f548e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 17:43:17 +0200 Subject: [PATCH 121/400] Added IsItemClicked() helper (#581) --- imgui.cpp | 8 ++++++-- imgui.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7aff89cc..0c7ef495 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1722,8 +1722,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) ImGuiWindow* window = GetCurrentWindow(); window->DC.LastItemID = id ? *id : 0; window->DC.LastItemRect = bb; - window->DC.LastItemHoveredAndUsable = false; - window->DC.LastItemHoveredRect = false; + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; if (IsClippedEx(bb, id, false)) return false; @@ -3056,6 +3055,11 @@ bool ImGui::IsItemActive() return false; } +bool ImGui::IsItemClicked(int mouse_button) +{ + return IsMouseClicked(mouse_button) && IsItemHovered(); +} + bool ImGui::IsAnyItemHovered() { return GImGui->HoveredId != 0 || GImGui->HoveredIdPreviousFrame != 0; diff --git a/imgui.h b/imgui.h index 11b63b8f..7e0d9b54 100644 --- a/imgui.h +++ b/imgui.h @@ -378,6 +378,7 @@ namespace ImGui IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? IMGUI_API bool IsItemHoveredRect(); // was the last item hovered by mouse? even if another item is active or window is blocked by popup while we are hovering this IMGUI_API bool IsItemActive(); // was 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 IsItemClicked(int mouse_button = 0); // was the last item clicked? (e.g. button/node just clicked on) IMGUI_API bool IsItemVisible(); // was the last item visible? (aka not out of sight due to clipping/scrolling.) IMGUI_API bool IsAnyItemHovered(); IMGUI_API bool IsAnyItemActive(); From 547f34cf22640526b63f02f50c73ef9409e8acab Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 17:43:51 +0200 Subject: [PATCH 122/400] Refactor ButtonBehavior(), fixed double-click mode also triggering on single-click (relate to #516) --- imgui.cpp | 40 ++++++++++++++++++++-------------------- imgui_internal.h | 19 ++++++++++--------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0c7ef495..aced3a99 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5264,6 +5264,9 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool return false; } + if ((flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick)) == 0) + flags |= ImGuiButtonFlags_PressedOnClickRelease; + bool pressed = false; bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0); if (hovered) @@ -5271,32 +5274,29 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetHoveredID(id); if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { - if (g.IO.MouseDoubleClicked[0] && (flags & ImGuiButtonFlags_PressedOnDoubleClick)) + if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0]) // Most common type { - pressed = true; - } - else if (g.IO.MouseClicked[0]) - { - if (flags & ImGuiButtonFlags_PressedOnClick) - { - pressed = true; - SetActiveID(0); - } - else - { - SetActiveID(id, window); - } + SetActiveID(id, window); // Hold on ID FocusWindow(window); } - else if (g.IO.MouseReleased[0] && (flags & ImGuiButtonFlags_PressedOnRelease)) + if ((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) + { + pressed = true; + SetActiveID(0); + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0]) + { + pressed = true; + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) { pressed = true; SetActiveID(0); } - else if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && ImGui::IsMouseClicked(0, true)) - { + if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && ImGui::IsMouseClicked(0, true)) pressed = true; - } } } @@ -5309,7 +5309,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } else { - if (hovered) + if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease)) pressed = true; SetActiveID(0); } @@ -8242,7 +8242,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick; if (flags & ImGuiSelectableFlags_MenuItem) button_flags |= ImGuiButtonFlags_PressedOnClick|ImGuiButtonFlags_PressedOnRelease; if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled; - if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick; + if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; bool hovered, held; bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags); if (flags & ImGuiSelectableFlags_Disabled) diff --git a/imgui_internal.h b/imgui_internal.h index d099d3b7..db4b9ccd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -154,15 +154,16 @@ inline void operator delete(void*, ImPlacementNewDummy, void*) {} enum ImGuiButtonFlags_ { ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat - ImGuiButtonFlags_PressedOnClick = 1 << 1, // return pressed on click (default requires click+release) - ImGuiButtonFlags_PressedOnRelease = 1 << 2, // return pressed on release (default requires click+release) - ImGuiButtonFlags_PressedOnDoubleClick = 1 << 3, // return pressed on double-click (default requires click+release) - ImGuiButtonFlags_FlattenChilds = 1 << 4, // allow interaction even if a child window is overlapping - ImGuiButtonFlags_DontClosePopups = 1 << 5, // disable automatically closing parent popup on press - ImGuiButtonFlags_Disabled = 1 << 6, // disable interaction - ImGuiButtonFlags_AlignTextBaseLine = 1 << 7, // vertically align button to match text baseline - ButtonEx() only - ImGuiButtonFlags_NoKeyModifiers = 1 << 8, // disable interaction if a key modifier is held - ImGuiButtonFlags_AllowOverlapMode = 1 << 9 // require previous frame HoveredId to either match id or be null before being usable + ImGuiButtonFlags_PressedOnClickRelease = 1 << 1, // (default) return pressed on click+release on same item (default if no PressedOn** flag is set) + ImGuiButtonFlags_PressedOnClick = 1 << 2, // return pressed on click (default requires click+release) + ImGuiButtonFlags_PressedOnRelease = 1 << 3, // return pressed on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4, // return pressed on double-click (default requires click+release) + ImGuiButtonFlags_FlattenChilds = 1 << 5, // allow interaction even if a child window is overlapping + ImGuiButtonFlags_DontClosePopups = 1 << 6, // disable automatically closing parent popup on press + ImGuiButtonFlags_Disabled = 1 << 7, // disable interaction + ImGuiButtonFlags_AlignTextBaseLine = 1 << 8, // vertically align button to match text baseline - ButtonEx() only + ImGuiButtonFlags_NoKeyModifiers = 1 << 9, // disable interaction if a key modifier is held + ImGuiButtonFlags_AllowOverlapMode = 1 << 10 // require previous frame HoveredId to either match id or be null before being usable }; enum ImGuiSliderFlags_ From a38fd2e186e59973d7a778bb4bbd434f2f5dbddf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 17:45:31 +0200 Subject: [PATCH 123/400] Added TreeNodeEx() functions (#581, #600, #190) --- imgui.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++---------- imgui.h | 5 +++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index aced3a99..59b05e74 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5762,7 +5762,16 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags return opened; } -bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags, label, NULL); +} + +bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -5770,25 +5779,53 @@ bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) ImGuiState& g = *GImGui; const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - return TreeNodeBehavior(window->GetID(str_id), 0, g.TempBuffer, label_end); + return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiState& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +{ + return TreeNodeExV(str_id, 0, fmt, args); } bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) { - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; + return TreeNodeExV(ptr_id, 0, fmt, args); +} - ImGuiState& g = *GImGui; - const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - return TreeNodeBehavior(window->GetID(ptr_id ? ptr_id : fmt), 0, g.TempBuffer, label_end); +bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool opened = TreeNodeExV(str_id, flags, fmt, args); + va_end(args); + return opened; +} + +bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool opened = TreeNodeExV(ptr_id, flags, fmt, args); + va_end(args); + return opened; } bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) { va_list args; va_start(args, fmt); - bool opened = TreeNodeV(str_id, fmt, args); + bool opened = TreeNodeExV(str_id, 0, fmt, args); va_end(args); return opened; } @@ -5797,7 +5834,7 @@ bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) { va_list args; va_start(args, fmt); - bool opened = TreeNodeV(ptr_id, fmt, args); + bool opened = TreeNodeExV(ptr_id, 0, fmt, args); va_end(args); return opened; } diff --git a/imgui.h b/imgui.h index 7e0d9b54..66e1f5cf 100644 --- a/imgui.h +++ b/imgui.h @@ -312,6 +312,11 @@ namespace ImGui IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_PRINTFARGS(2); // " IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args); // " IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args); // " + IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); + IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_PRINTFARGS(3); + IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_PRINTFARGS(3); + IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args); + IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args); IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layout purpose IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); From 4c880b7106d79309fa6d0cdf065e4131431ce6ee Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 17:46:08 +0200 Subject: [PATCH 124/400] Added ImGuiTreeNodeFlags_OpenOnDoubleClick (#581, #516, #190) --- imgui.cpp | 3 ++- imgui.h | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 59b05e74..d9b970e0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5682,7 +5682,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return opened; } - bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowOverlapMode : 0)); + ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowOverlapMode : 0) | ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) ? ImGuiButtonFlags_PressedOnDoubleClick : 0); + bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); if (pressed) { opened = !opened; diff --git a/imgui.h b/imgui.h index 66e1f5cf..ae02c90e 100644 --- a/imgui.h +++ b/imgui.h @@ -530,6 +530,11 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when opened (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes). ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be opened + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Double-click to open node + //ImGuiTreeNodeFlags_OpenOnArrowOnly = 1 << 7, // FIXME: TODO: Can only click by + //ImGuiTreeNodeFlags_UnindentArrow = 1 << 8, // FIXME: TODO + //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 9, // FIXME: TODO: Extend hit box horizontally even if not framed + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 10, // FIXME: TODO: Automatically scroll on TreePop() if node got just opened and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; From dc8446d048b0dc021e4d0a407e05185424902f73 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 17:55:04 +0200 Subject: [PATCH 125/400] Demo: Added simple tree node selection demo (#581, #516, #190) --- imgui.h | 4 ++-- imgui_demo.cpp | 43 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index ae02c90e..ce484f8d 100644 --- a/imgui.h +++ b/imgui.h @@ -530,8 +530,8 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when opened (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes). ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be opened - ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Double-click to open node - //ImGuiTreeNodeFlags_OpenOnArrowOnly = 1 << 7, // FIXME: TODO: Can only click by + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node + //ImGuiTreeNodeFlags_OpenOnArrowOnly = 1 << 7, // FIXME: TODO //ImGuiTreeNodeFlags_UnindentArrow = 1 << 8, // FIXME: TODO //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 9, // FIXME: TODO: Extend hit box horizontally even if not framed //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 10, // FIXME: TODO: Automatically scroll on TreePop() if node got just opened and contents is not visible diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ac88f842..3a9df979 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -270,16 +270,45 @@ void ImGui::ShowTestWindow(bool* p_opened) { if (ImGui::TreeNode("Trees")) { - for (int i = 0; i < 5; i++) + if (ImGui::TreeNode("Basic trees")) { - if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) + for (int i = 0; i < 5; i++) + if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) + { + ImGui::Text("blah blah"); + ImGui::SameLine(); + if (ImGui::SmallButton("print")) printf("Child %d pressed", i); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("With selectable nodes")) + { + ShowHelpMarker("Click to select, CTRL+Click to toggle, double-click to open"); + static int selection_mask = 0x02; // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. + int node_clicked = -1; + for (int i = 0; i < 5; i++) { - ImGui::Text("blah blah"); - ImGui::SameLine(); - if (ImGui::SmallButton("print")) - printf("Child %d pressed", i); - ImGui::TreePop(); + ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnDoubleClick; + bool opened = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Child %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; + if (opened) + { + ImGui::Text("blah blah"); + ImGui::TreePop(); + } } + if (node_clicked != -1) + { + // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame. + if (ImGui::GetIO().KeyCtrl) + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else + selection_mask = (1 << node_clicked); // Click to single-select + } + ImGui::TreePop(); } ImGui::TreePop(); } From 470b88e9659f3f4fc9f043507347a5b2d55b463f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 20:02:25 +0200 Subject: [PATCH 126/400] ButtonBehavior(): ImGuiButtonFlags_PressedOnDoubleClick clears active id on double-click so that multiple flags don't trigger multiple times --- imgui.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d9b970e0..f2015e62 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1762,7 +1762,7 @@ bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs) { ImGuiWindow* window = GetCurrentWindowRead(); if (g.HoveredWindow == window || (flatten_childs && g.HoveredRootWindow == window->RootWindow)) - if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdAllowOverlap) && ImGui::IsMouseHoveringRect(bb.Min, bb.Max)) + if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdAllowOverlap) && IsMouseHoveringRect(bb.Min, bb.Max)) if (IsWindowContentHoverable(g.HoveredRootWindow)) return true; } @@ -5279,17 +5279,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetActiveID(id, window); // Hold on ID FocusWindow(window); } - if ((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) + if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0])) { pressed = true; SetActiveID(0); FocusWindow(window); } - if ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0]) - { - pressed = true; - FocusWindow(window); - } if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) { pressed = true; From df764c21d6f82a54ce6c8cb5dffbf6839eb19a4c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 20:04:48 +0200 Subject: [PATCH 127/400] Bullet(), BulletText(): slightly bigger. less polygons --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f2015e62..43f2c63e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5915,8 +5915,8 @@ void ImGui::Bullet() } // Render - const float bullet_size = g.FontSize*0.15f; - window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text)); + const float bullet_size = g.FontSize*0.20f; + window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text), 8); // Stay on same line ImGui::SameLine(0, style.FramePadding.x*2); @@ -5943,8 +5943,8 @@ void ImGui::BulletTextV(const char* fmt, va_list args) return; // Render - const float bullet_size = g.FontSize*0.15f; - window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text)); + const float bullet_size = g.FontSize*0.20f; + window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text), 8); RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end); } From f79b2d6ce38e119e72a2a1a04a617f05be7ac802 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 20:12:14 +0200 Subject: [PATCH 128/400] TreeNode: added ImGuiTreeNodeFlags_OpenOnArrow flag (#581, #324, #190) --- imgui.cpp | 21 ++++++++++++++++++--- imgui.h | 11 ++++++----- imgui_demo.cpp | 8 ++++---- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 43f2c63e..b632e398 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5677,12 +5677,27 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return opened; } - ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowOverlapMode : 0) | ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) ? ImGuiButtonFlags_PressedOnDoubleClick : 0); + // Flags that affects opening behavior: + // - 0(default) ..................... single-click anywhere to open + // - OpenOnDoubleClick .............. double-click anywhere to open + // - OpenOnArrow .................... single-click on arrow to open + // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open + ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowOverlapMode) ? ImGuiButtonFlags_AllowOverlapMode : 0); + if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); if (pressed) { - opened = !opened; - window->DC.StateStorage->SetInt(id, opened); + bool toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)); + if (flags & ImGuiTreeNodeFlags_OpenOnArrow) + toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + collapser_width, interact_bb.Max.y)); + if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + toggled |= g.IO.MouseDoubleClicked[0]; + if (toggled) + { + opened = !opened; + window->DC.StateStorage->SetInt(id, opened); + } } if (flags & ImGuiTreeNodeFlags_AllowOverlapMode) SetItemAllowOverlap(); diff --git a/imgui.h b/imgui.h index ce484f8d..c82e1422 100644 --- a/imgui.h +++ b/imgui.h @@ -528,13 +528,14 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) ImGuiTreeNodeFlags_AllowOverlapMode = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when opened (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack - ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes). + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be opened ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node - //ImGuiTreeNodeFlags_OpenOnArrowOnly = 1 << 7, // FIXME: TODO - //ImGuiTreeNodeFlags_UnindentArrow = 1 << 8, // FIXME: TODO - //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 9, // FIXME: TODO: Extend hit box horizontally even if not framed - //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 10, // FIXME: TODO: Automatically scroll on TreePop() if node got just opened and contents is not visible + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. + //ImGuiTreeNodeFlags_AlwaysOpen = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + //ImGuiTreeNodeFlags_UnindentArrow = 1 << 9, // FIXME: TODO: Unindent tree so that Label is aligned to current X position + //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 10, // FIXME: TODO: Extend hit box horizontally even if not framed + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 11, // FIXME: TODO: Automatically scroll on TreePop() if node got just opened and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3a9df979..acdc0330 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -285,18 +285,18 @@ void ImGui::ShowTestWindow(bool* p_opened) if (ImGui::TreeNode("With selectable nodes")) { - ShowHelpMarker("Click to select, CTRL+Click to toggle, double-click to open"); + ShowHelpMarker("Click to select, CTRL+Click to toggle, click on arrows to open"); static int selection_mask = 0x02; // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. int node_clicked = -1; - for (int i = 0; i < 5; i++) + for (int i = 0; i < 6; i++) { - ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnDoubleClick; + ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; bool opened = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Child %d", i); if (ImGui::IsItemClicked()) node_clicked = i; if (opened) { - ImGui::Text("blah blah"); + ImGui::Text("Blah blah"); ImGui::TreePop(); } } From 9733f4fa244a11e096440676810156975e6a4483 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 20:19:28 +0200 Subject: [PATCH 129/400] Internal RenderBullet() helper. --- imgui.cpp | 18 ++++++++++-------- imgui_internal.h | 4 +++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b632e398..00990ba5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2741,6 +2741,12 @@ void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool window->DrawList->AddTriangleFilled(a, b, c, GetColorU32(ImGuiCol_Text)); } +void ImGui::RenderBullet(ImVec2 pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8); +} + void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col) { ImGuiState& g = *GImGui; @@ -5929,12 +5935,9 @@ void ImGui::Bullet() return; } - // Render - const float bullet_size = g.FontSize*0.20f; - window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text), 8); - - // Stay on same line - ImGui::SameLine(0, style.FramePadding.x*2); + // Render and stay on same line + RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); + SameLine(0, style.FramePadding.x*2); } // Text with a little bullet aligned to the typical tree node. @@ -5958,8 +5961,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) return; // Render - const float bullet_size = g.FontSize*0.20f; - window->DrawList->AddCircleFilled(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), bullet_size, GetColorU32(ImGuiCol_Text), 8); + RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end); } diff --git a/imgui_internal.h b/imgui_internal.h index db4b9ccd..0ef0b847 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -699,12 +699,14 @@ namespace ImGui inline IMGUI_API ImU32 GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } // NB: All position are in absolute pixels coordinates (not window coordinates) - // FIXME: Refactor all RenderText* functions into one. + // FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp! + // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool opened, float scale = 1.0f, bool shadow = false); + IMGUI_API void RenderBullet(ImVec2 pos); IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. From bb674ccee6d1539dbb4c6f01eb4b22042c3f38cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 21:15:46 +0200 Subject: [PATCH 130/400] TreeNode: added ImGuiTreeNodeFlags_AlwaysOpen flag (#581, #324) --- imgui.cpp | 10 ++++++++-- imgui.h | 4 ++-- imgui_demo.cpp | 5 ++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 00990ba5..95bb2aa2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5600,6 +5600,9 @@ void ImGui::LogButtons() bool ImGui::TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags) { + if (flags & ImGuiTreeNodeFlags_AlwaysOpen) + return true; + // We only write to the tree storage if the user clicks (or explicitely use SetNextTreeNode*** functions) ImGuiState& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -5692,7 +5695,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); - if (pressed) + if (pressed && !(flags & ImGuiTreeNodeFlags_AlwaysOpen)) { bool toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)); if (flags & ImGuiTreeNodeFlags_OpenOnArrow) @@ -5736,7 +5739,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (hovered || (flags & ImGuiTreeNodeFlags_Selected)) RenderFrame(bb.Min, bb.Max, col, false); - RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); + if (flags & ImGuiTreeNodeFlags_AlwaysOpen) + RenderBullet(bb.Min + ImVec2((padding.x + collapser_width) * 0.5f, g.FontSize*0.50f + text_base_offset_y)); + else + RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); if (g.LogEnabled) LogRenderedText(text_pos, ">"); RenderText(text_pos, label, label_end, false); diff --git a/imgui.h b/imgui.h index c82e1422..dd3c9fbf 100644 --- a/imgui.h +++ b/imgui.h @@ -532,7 +532,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be opened ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. - //ImGuiTreeNodeFlags_AlwaysOpen = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_AlwaysOpen = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). //ImGuiTreeNodeFlags_UnindentArrow = 1 << 9, // FIXME: TODO: Unindent tree so that Label is aligned to current X position //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 10, // FIXME: TODO: Extend hit box horizontally even if not framed //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 11, // FIXME: TODO: Automatically scroll on TreePop() if node got just opened and contents is not visible @@ -695,7 +695,7 @@ struct ImGuiStyle ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - float IndentSpacing; // Horizontal indentation when e.g. entering a tree node + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2) float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar float ScrollbarRounding; // Radius of grab corners for scrollbar diff --git a/imgui_demo.cpp b/imgui_demo.cpp index acdc0330..92e883a1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -291,11 +291,14 @@ void ImGui::ShowTestWindow(bool* p_opened) for (int i = 0; i < 6; i++) { ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - bool opened = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Child %d", i); + if (i >= 3) + node_flags |= ImGuiTreeNodeFlags_AlwaysOpen; + bool opened = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable %s %d", (i >= 3) ? "Leaf" : "Node", i); if (ImGui::IsItemClicked()) node_clicked = i; if (opened) { + ImGui::Text("Blah blah"); ImGui::Text("Blah blah"); ImGui::TreePop(); } From b93040e600a6788f73443cfb49a10f0382025977 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 23:46:48 +0200 Subject: [PATCH 131/400] TreeNode: minor tidying up (#581, #324) --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 95bb2aa2..b4fa6c0d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5671,7 +5671,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1; } - const float collapser_width = g.FontSize + (display_frame ? padding.x*2 : padding.x); + const float text_offset_x = g.FontSize + (display_frame ? padding.x*3 : padding.x*2); // Collapser arrow width + Spacing const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser ItemSize(ImVec2(text_width, frame_height), text_base_offset_y); @@ -5699,7 +5699,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { bool toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)); if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + collapser_width, interact_bb.Max.y)); + toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)); if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) toggled |= g.IO.MouseDoubleClicked[0]; if (toggled) @@ -5713,7 +5713,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); - const ImVec2 text_pos = bb.Min + padding + ImVec2(collapser_width, text_base_offset_y); + const ImVec2 text_pos = bb.Min + ImVec2(text_offset_x, padding.y + text_base_offset_y); if (display_frame) { // Framed type @@ -5740,7 +5740,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l RenderFrame(bb.Min, bb.Max, col, false); if (flags & ImGuiTreeNodeFlags_AlwaysOpen) - RenderBullet(bb.Min + ImVec2((padding.x + collapser_width) * 0.5f, g.FontSize*0.50f + text_base_offset_y)); + RenderBullet(bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); else RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); if (g.LogEnabled) From 13df4668d1573cd887798157b3904762c0175b09 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 23:47:58 +0200 Subject: [PATCH 132/400] Added GetTreeNodeToLabelSpacing() helper - tentative name (#581, #324) --- imgui.cpp | 11 +++++++++++ imgui.h | 1 + 2 files changed, 12 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index b4fa6c0d..b1ffa3e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5871,6 +5871,17 @@ bool ImGui::TreeNode(const char* label) return TreeNodeBehavior(window->GetID(label), 0, label, NULL); } +float ImGui::GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags) +{ + ImGuiState& g = *GImGui; + float off_from_start; + if (flags & ImGuiTreeNodeFlags_Framed) + off_from_start = g.FontSize + (g.Style.FramePadding.x * 3.0f) - ((float)(int)(g.CurrentWindow->WindowPadding.x*0.5f) - 1); + else + off_from_start = g.FontSize + (g.Style.FramePadding.x * 2.0f); + return off_from_start; +} + void ImGui::SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond) { ImGuiState& g = *GImGui; diff --git a/imgui.h b/imgui.h index dd3c9fbf..0b76157b 100644 --- a/imgui.h +++ b/imgui.h @@ -321,6 +321,7 @@ namespace ImGui IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node/collapsing header to be opened. + IMGUI_API float GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags = 0); // return horizontal distance between cursor and text label due to collapsing node. == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header From 4170b4847d628c7116228a853eed3ae55493cc69 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 May 2016 23:49:10 +0200 Subject: [PATCH 133/400] Style: Changed default IndentSpacing from 22 to 21 (#581, #324) --- imgui.cpp | 2 +- imgui.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b1ffa3e3..fad187b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -708,7 +708,7 @@ ImGuiStyle::ImGuiStyle() ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node + IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar diff --git a/imgui.h b/imgui.h index 0b76157b..5258a5b9 100644 --- a/imgui.h +++ b/imgui.h @@ -696,7 +696,7 @@ struct ImGuiStyle ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2) + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar float ScrollbarRounding; // Radius of grab corners for scrollbar From 4f34ed5010ce2350ebb27379281ca8471b4a7abe Mon Sep 17 00:00:00 2001 From: Anton Holmberg Date: Sun, 1 May 2016 16:18:31 -0700 Subject: [PATCH 134/400] Fix typo in Programmer guide --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index fad187b4..97a935ec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -78,7 +78,7 @@ - read the FAQ below this section! - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. - call and read ImGui::ShowTestWindow() for demo code demonstrating most features. - - see examples/ folder for standalone sample applications. Prefer reading examples/opengl_example/ first at it is the simplest. + - see examples/ folder for standalone sample applications. Prefer reading examples/opengl_example/ first as it is the simplest. you may be able to grab and copy a ready made imgui_impl_*** file from the examples/. - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). From 89d50261873504c96ce2e10bd53d26c61c5c67e3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 May 2016 12:32:16 +0200 Subject: [PATCH 135/400] Renamed majority of use of "opened" to "open" for clarity. Renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(). (#625, #579) --- imgui.cpp | 235 ++++++++++++++++++++++++----------------------- imgui.h | 30 +++--- imgui_demo.cpp | 86 ++++++++--------- imgui_internal.h | 14 +-- 4 files changed, 183 insertions(+), 182 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 97a935ec..70649fdb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -53,7 +53,7 @@ ============== - double-click title bar to collapse window - - click upper right corner to close a window, available when 'bool* p_opened' is passed to ImGui::Begin() + - click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin() - click and drag on lower right corner to resize window - click and drag on any empty space to move window - double-click/double-tap on lower right corner grip to auto-fit to content @@ -152,6 +152,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). @@ -196,7 +197,7 @@ - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "opened" state of a popup. BeginPopup() returns true if the popup is opened. + - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete). - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API @@ -365,7 +366,7 @@ TreePop(); } - - When working with trees, ID are used to preserve the opened/closed state of each tree node. + - When working with trees, ID are used to preserve the open/close state of each tree node. Depending on your use cases you may want to use strings, indices or pointers as ID. e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! @@ -444,7 +445,7 @@ - window: background options for child windows, border option (disable rounding) - window: add a way to clear an existing window instead of appending (e.g. for tooltip override using a consistent api rather than the deferred tooltip) - window: resizing from any sides? + mouse cursor directives for app. -!- window: begin with *p_opened == false should return false. +!- window: begin with *p_open == false should return false. - window: get size/pos helpers given names (see discussion in #249) - window: a collapsed window can be stuck behind the main menu bar? - window: when window is small, prioritize resize button over close button. @@ -2032,7 +2033,7 @@ void ImGui::NewFrame() for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) { if (g.IO.MouseClicked[i]) - g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenedPopupStack.empty()); + g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty()); mouse_any_down |= g.IO.MouseDown[i]; if (g.IO.MouseDown[i]) if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[mouse_earliest_button_down] > g.IO.MouseClickedTime[i]) @@ -2042,7 +2043,7 @@ void ImGui::NewFrame() if (g.CaptureMouseNextFrame != -1) g.IO.WantCaptureMouse = (g.CaptureMouseNextFrame != 0); else - g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.ActiveId != 0) || (!g.OpenedPopupStack.empty()); + g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.ActiveId != 0) || (!g.OpenPopupStack.empty()); g.IO.WantCaptureKeyboard = (g.CaptureKeyboardNextFrame != -1) ? (g.CaptureKeyboardNextFrame != 0) : (g.ActiveId != 0); g.IO.WantTextInput = (g.ActiveId != 0 && g.InputTextState.Id == g.ActiveId); g.MouseCursor = ImGuiMouseCursor_Arrow; @@ -2141,7 +2142,7 @@ void ImGui::Shutdown() g.ColorModifiers.clear(); g.StyleModifiers.clear(); g.FontStack.clear(); - g.OpenedPopupStack.clear(); + g.OpenPopupStack.clear(); g.CurrentPopupStack.clear(); for (int i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) g.RenderDrawLists[i].clear(); @@ -2712,7 +2713,7 @@ void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, } // Render a triangle to denote expanded/collapsed state -void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool shadow) +void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale, bool shadow) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -2722,7 +2723,7 @@ void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale, bool ImVec2 center = p_min + ImVec2(h*0.50f, h*0.50f*scale); ImVec2 a, b, c; - if (opened) + if (is_open) { center.y -= r*0.25f; a = center + ImVec2(0,1)*r; @@ -2994,7 +2995,7 @@ ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() { ImGuiState& g = *GImGui; if (g.CurrentPopupStack.Size > 0) - return g.OpenedPopupStack[g.CurrentPopupStack.Size-1].MousePosOnOpen; + return g.OpenPopupStack[g.CurrentPopupStack.Size-1].MousePosOnOpen; return g.IO.MousePos; } @@ -3157,8 +3158,8 @@ void ImGui::EndTooltip() static bool IsPopupOpen(ImGuiID id) { ImGuiState& g = *GImGui; - const bool opened = g.OpenedPopupStack.Size > g.CurrentPopupStack.Size && g.OpenedPopupStack[g.CurrentPopupStack.Size].PopupID == id; - return opened; + const bool is_open = g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupID == id; + return is_open; } // Mark popup as open (toggle toward open state). @@ -3172,12 +3173,12 @@ void ImGui::OpenPopupEx(const char* str_id, bool reopen_existing) ImGuiID id = window->GetID(str_id); int current_stack_size = g.CurrentPopupStack.Size; ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) - if (g.OpenedPopupStack.Size < current_stack_size + 1) - g.OpenedPopupStack.push_back(popup_ref); - else if (reopen_existing || g.OpenedPopupStack[current_stack_size].PopupID != id) + if (g.OpenPopupStack.Size < current_stack_size + 1) + g.OpenPopupStack.push_back(popup_ref); + else if (reopen_existing || g.OpenPopupStack[current_stack_size].PopupID != id) { - g.OpenedPopupStack.resize(current_stack_size+1); - g.OpenedPopupStack[current_stack_size] = popup_ref; + g.OpenPopupStack.resize(current_stack_size+1); + g.OpenPopupStack[current_stack_size] = popup_ref; } } @@ -3189,7 +3190,7 @@ void ImGui::OpenPopup(const char* str_id) static void CloseInactivePopups() { ImGuiState& g = *GImGui; - if (g.OpenedPopupStack.empty()) + if (g.OpenPopupStack.empty()) return; // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. @@ -3197,9 +3198,9 @@ static void CloseInactivePopups() int n = 0; if (g.FocusedWindow) { - for (n = 0; n < g.OpenedPopupStack.Size; n++) + for (n = 0; n < g.OpenPopupStack.Size; n++) { - ImGuiPopupRef& popup = g.OpenedPopupStack[n]; + ImGuiPopupRef& popup = g.OpenPopupStack[n]; if (!popup.Window) continue; IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); @@ -3207,21 +3208,21 @@ static void CloseInactivePopups() continue; bool has_focus = false; - for (int m = n; m < g.OpenedPopupStack.Size && !has_focus; m++) - has_focus = (g.OpenedPopupStack[m].Window && g.OpenedPopupStack[m].Window->RootWindow == g.FocusedWindow->RootWindow); + for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++) + has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == g.FocusedWindow->RootWindow); if (!has_focus) break; } } - if (n < g.OpenedPopupStack.Size) // This test is not required but it allows to set a useful breakpoint on the line below - g.OpenedPopupStack.resize(n); + if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a useful breakpoint on the line below + g.OpenPopupStack.resize(n); } static ImGuiWindow* GetFrontMostModalRootWindow() { ImGuiState& g = *GImGui; - for (int n = g.OpenedPopupStack.Size-1; n >= 0; n--) - if (ImGuiWindow* front_most_popup = g.OpenedPopupStack.Data[n].Window) + for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) + if (ImGuiWindow* front_most_popup = g.OpenPopupStack.Data[n].Window) if (front_most_popup->Flags & ImGuiWindowFlags_Modal) return front_most_popup; return NULL; @@ -3231,10 +3232,10 @@ static void ClosePopupToLevel(int remaining) { ImGuiState& g = *GImGui; if (remaining > 0) - ImGui::FocusWindow(g.OpenedPopupStack[remaining-1].Window); + ImGui::FocusWindow(g.OpenPopupStack[remaining-1].Window); else - ImGui::FocusWindow(g.OpenedPopupStack[0].ParentWindow); - g.OpenedPopupStack.resize(remaining); + ImGui::FocusWindow(g.OpenPopupStack[0].ParentWindow); + g.OpenPopupStack.resize(remaining); } static void ClosePopup(ImGuiID id) @@ -3242,7 +3243,7 @@ static void ClosePopup(ImGuiID id) if (!IsPopupOpen(id)) return; ImGuiState& g = *GImGui; - ClosePopupToLevel(g.OpenedPopupStack.Size - 1); + ClosePopupToLevel(g.OpenPopupStack.Size - 1); } // Close the popup we have begin-ed into. @@ -3250,9 +3251,9 @@ void ImGui::CloseCurrentPopup() { ImGuiState& g = *GImGui; int popup_idx = g.CurrentPopupStack.Size - 1; - if (popup_idx < 0 || popup_idx > g.OpenedPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupID != g.OpenedPopupStack[popup_idx].PopupID) + if (popup_idx < 0 || popup_idx > g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupID != g.OpenPopupStack[popup_idx].PopupID) return; - while (popup_idx > 0 && g.OpenedPopupStack[popup_idx].Window && (g.OpenedPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) + while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) popup_idx--; ClosePopupToLevel(popup_idx); } @@ -3284,18 +3285,18 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) else ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame - bool opened = ImGui::Begin(name, NULL, flags); + bool is_open = ImGui::Begin(name, NULL, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) g.CurrentWindow->Flags &= ~ImGuiWindowFlags_ShowBorders; - if (!opened) // opened can be 'false' when the popup is completely clipped (e.g. zero size display) + if (!is_open) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) ImGui::EndPopup(); - return opened; + return is_open; } bool ImGui::BeginPopup(const char* str_id) { - if (GImGui->OpenedPopupStack.Size <= GImGui->CurrentPopupStack.Size) // Early out for performance + if (GImGui->OpenPopupStack.Size <= GImGui->CurrentPopupStack.Size) // Early out for performance { ClearSetNextWindowData(); // We behave like Begin() and need to consume those values return false; @@ -3303,7 +3304,7 @@ bool ImGui::BeginPopup(const char* str_id) return BeginPopupEx(str_id, ImGuiWindowFlags_ShowBorders); } -bool ImGui::BeginPopupModal(const char* name, bool* p_opened, ImGuiWindowFlags extra_flags) +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -3315,16 +3316,16 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_opened, ImGuiWindowFlags e } ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoSavedSettings; - bool opened = ImGui::Begin(name, p_opened, flags); - if (!opened || (p_opened && !*p_opened)) // Opened can be 'false' when the popup is completely clipped (e.g. zero size display) + bool is_open = ImGui::Begin(name, p_open, flags); + if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) { ImGui::EndPopup(); - if (opened) + if (is_open) ClosePopup(id); return false; } - return opened; + return is_open; } void ImGui::EndPopup() @@ -3583,14 +3584,14 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). // You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. -// - Passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. +// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin(). -bool ImGui::Begin(const char* name, bool* p_opened, ImGuiWindowFlags flags) +bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { - return ImGui::Begin(name, p_opened, ImVec2(0.f, 0.f), -1.0f, flags); + return ImGui::Begin(name, p_open, ImVec2(0.f, 0.f), -1.0f, flags); } -bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags) +bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags) { ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; @@ -3627,7 +3628,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ bool window_was_active = (window->LastFrameActive == current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on if (flags & ImGuiWindowFlags_Popup) { - ImGuiPopupRef& popup_ref = g.OpenedPopupStack[g.CurrentPopupStack.Size]; + ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; window_was_active &= (window->PopupID == popup_ref.PopupID); window_was_active &= (window == popup_ref.Window); popup_ref.Window = window; @@ -4085,12 +4086,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) { - if (p_opened != NULL) + if (p_open != NULL) { const float pad = 2.0f; const float rad = (window->TitleBarHeight() - pad*2.0f) * 0.5f; if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad)) - *p_opened = false; + *p_open = false; } const ImVec2 text_size = CalcTextSize(name, NULL, true); @@ -4099,9 +4100,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ ImVec2 text_min = window->Pos + style.FramePadding; ImVec2 text_max = window->Pos + ImVec2(window->Size.x - style.FramePadding.x, style.FramePadding.y*2 + text_size.y); - ImVec2 clip_max = ImVec2(window->Pos.x + window->Size.x - (p_opened ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() + ImVec2 clip_max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() bool pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0; - bool pad_right = (p_opened != NULL); + bool pad_right = (p_open != NULL); if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; @@ -5598,7 +5599,7 @@ void ImGui::LogButtons() LogToClipboard(g.LogAutoExpandMaxDepth); } -bool ImGui::TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags) +bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) { if (flags & ImGuiTreeNodeFlags_AlwaysOpen) return true; @@ -5608,13 +5609,13 @@ bool ImGui::TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags) ImGuiWindow* window = g.CurrentWindow; ImGuiStorage* storage = window->DC.StateStorage; - bool opened; - if (g.SetNextTreeNodeOpenedCond != 0) + bool is_open; + if (g.SetNextTreeNodeOpenCond != 0) { - if (g.SetNextTreeNodeOpenedCond & ImGuiSetCond_Always) + if (g.SetNextTreeNodeOpenCond & ImGuiSetCond_Always) { - opened = g.SetNextTreeNodeOpenedVal; - storage->SetInt(id, opened); + is_open = g.SetNextTreeNodeOpenVal; + storage->SetInt(id, is_open); } else { @@ -5622,27 +5623,27 @@ bool ImGui::TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags) const int stored_value = storage->GetInt(id, -1); if (stored_value == -1) { - opened = g.SetNextTreeNodeOpenedVal; - storage->SetInt(id, opened); + is_open = g.SetNextTreeNodeOpenVal; + storage->SetInt(id, is_open); } else { - opened = stored_value != 0; + is_open = stored_value != 0; } } - g.SetNextTreeNodeOpenedCond = 0; + g.SetNextTreeNodeOpenCond = 0; } else { - opened = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; + is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; } // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). // NB- If we are above max depth we still allow manually opened nodes to be logged. if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth) - opened = true; + is_open = true; - return opened; + return is_open; } bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) @@ -5678,12 +5679,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing // (Ideally we'd want to add a flag for the user to specify we want want the hit test to be done up to the right side of the content or not) const ImRect interact_bb = display_frame ? bb : ImRect(bb.Min.x, bb.Min.y, bb.Min.x + text_width + style.ItemSpacing.x*2, bb.Max.y); - bool opened = TreeNodeBehaviorIsOpened(id, flags); + bool is_open = TreeNodeBehaviorIsOpen(id, flags); if (!ItemAdd(interact_bb, &id)) { - if (opened && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushRawID(id); - return opened; + return is_open; } // Flags that affects opening behavior: @@ -5704,8 +5705,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l toggled |= g.IO.MouseDoubleClicked[0]; if (toggled) { - opened = !opened; - window->DC.StateStorage->SetInt(id, opened); + is_open = !is_open; + window->DC.StateStorage->SetInt(id, is_open); } } if (flags & ImGuiTreeNodeFlags_AllowOverlapMode) @@ -5718,7 +5719,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { // Framed type RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), opened, 1.0f, true); + RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), is_open, 1.0f, true); if (g.LogEnabled) { // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. @@ -5742,15 +5743,15 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_AlwaysOpen) RenderBullet(bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); else - RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), opened, 0.70f, false); + RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open, 0.70f, false); if (g.LogEnabled) LogRenderedText(text_pos, ">"); RenderText(text_pos, label, label_end, false); } - if (opened && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushRawID(id); - return opened; + return is_open; } bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) @@ -5772,7 +5773,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags return false; ImGuiID id = window->GetID(label); - bool opened = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen | (p_open ? ImGuiTreeNodeFlags_AllowOverlapMode : 0), label); + bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen | (p_open ? ImGuiTreeNodeFlags_AllowOverlapMode : 0), label); if (p_open) { // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. @@ -5782,7 +5783,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags *p_open = false; } - return opened; + return is_open; } bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) @@ -5830,36 +5831,36 @@ bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* { va_list args; va_start(args, fmt); - bool opened = TreeNodeExV(str_id, flags, fmt, args); + bool is_open = TreeNodeExV(str_id, flags, fmt, args); va_end(args); - return opened; + return is_open; } bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) { va_list args; va_start(args, fmt); - bool opened = TreeNodeExV(ptr_id, flags, fmt, args); + bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); va_end(args); - return opened; + return is_open; } bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) { va_list args; va_start(args, fmt); - bool opened = TreeNodeExV(str_id, 0, fmt, args); + bool is_open = TreeNodeExV(str_id, 0, fmt, args); va_end(args); - return opened; + return is_open; } bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) { va_list args; va_start(args, fmt); - bool opened = TreeNodeExV(ptr_id, 0, fmt, args); + bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); va_end(args); - return opened; + return is_open; } bool ImGui::TreeNode(const char* label) @@ -5882,11 +5883,11 @@ float ImGui::GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags) return off_from_start; } -void ImGui::SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond) +void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond) { ImGuiState& g = *GImGui; - g.SetNextTreeNodeOpenedVal = opened; - g.SetNextTreeNodeOpenedCond = cond ? cond : ImGuiSetCond_Always; + g.SetNextTreeNodeOpenVal = is_open; + g.SetNextTreeNodeOpenCond = cond ? cond : ImGuiSetCond_Always; } void ImGui::PushID(const char* str_id) @@ -8171,12 +8172,12 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const float arrow_size = (g.FontSize + style.FramePadding.x * 2.0f); const bool hovered = IsHovered(frame_bb, id); - bool popup_opened = IsPopupOpen(id); + bool popup_open = IsPopupOpen(id); bool popup_opened_now = false; const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(popup_opened || hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING + RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(popup_open || hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING RenderCollapseTriangle(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y) + style.FramePadding, true); if (*current_item >= 0 && *current_item < items_count) @@ -8203,7 +8204,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi { FocusWindow(window); OpenPopup(label); - popup_opened = popup_opened_now = true; + popup_open = popup_opened_now = true; } } } @@ -8555,9 +8556,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled) ImGuiWindow* backed_focused_window = g.FocusedWindow; bool pressed; - bool opened = IsPopupOpen(id); - bool menuset_opened = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenedPopupStack.Size > g.CurrentPopupStack.Size && g.OpenedPopupStack[g.CurrentPopupStack.Size].ParentMenuSet == window->GetID("##menus")); - if (menuset_opened) + bool menu_is_open = IsPopupOpen(id); + bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentMenuSet == window->GetID("##menus")); + if (menuset_is_open) g.FocusedWindow = window; ImVec2 popup_pos, pos = window->DC.CursorPos; @@ -8567,7 +8568,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; - pressed = ImGui::Selectable(label, opened, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + pressed = ImGui::Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); ImGui::PopStyleVar(); ImGui::SameLine(); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); @@ -8577,14 +8578,14 @@ bool ImGui::BeginMenu(const char* label, bool enabled) popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame float extra_w = ImMax(0.0f, ImGui::GetContentRegionAvail().x - w); - pressed = ImGui::Selectable(label, opened, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + pressed = ImGui::Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); if (!enabled) ImGui::PopStyleColor(); } bool hovered = enabled && IsHovered(window->DC.LastItemRect, id); - if (menuset_opened) + if (menuset_is_open) g.FocusedWindow = backed_focused_window; bool want_open = false, want_close = false; @@ -8592,9 +8593,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled) { // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. bool moving_within_opened_triangle = false; - if (g.HoveredWindow == window && g.OpenedPopupStack.Size > g.CurrentPopupStack.Size && g.OpenedPopupStack[g.CurrentPopupStack.Size].ParentWindow == window) + if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window) { - if (ImGuiWindow* next_window = g.OpenedPopupStack[g.CurrentPopupStack.Size].Window) + if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window) { ImRect next_window_rect = next_window->Rect(); ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; @@ -8609,39 +8610,39 @@ bool ImGui::BeginMenu(const char* label, bool enabled) } } - want_close = (opened && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle); - want_open = (!opened && hovered && !moving_within_opened_triangle) || (!opened && hovered && pressed); + want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle); + want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed); } - else if (opened && pressed && menuset_opened) // menu-bar: click open menu to close + else if (menu_is_open && pressed && menuset_is_open) // menu-bar: click open menu to close { want_close = true; - want_open = opened = false; + want_open = menu_is_open = false; } - else if (pressed || (hovered && menuset_opened && !opened)) // menu-bar: first click to open, then hover to open others + else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // menu-bar: first click to open, then hover to open others want_open = true; if (want_close && IsPopupOpen(id)) ClosePopupToLevel(GImGui->CurrentPopupStack.Size); - if (!opened && want_open && g.OpenedPopupStack.Size > g.CurrentPopupStack.Size) + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size) { // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. ImGui::OpenPopup(label); return false; } - opened |= want_open; + menu_is_open |= want_open; if (want_open) ImGui::OpenPopup(label); - if (opened) + if (menu_is_open) { ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); ImGuiWindowFlags flags = ImGuiWindowFlags_ShowBorders | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu); - opened = BeginPopupEx(label, flags); // opened can be 'false' when the popup is completely clipped (e.g. zero size display) + menu_is_open = BeginPopupEx(label, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) } - return opened; + return menu_is_open; } void ImGui::EndMenu() @@ -9399,9 +9400,9 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} // HELP //----------------------------------------------------------------------------- -void ImGui::ShowMetricsWindow(bool* opened) +void ImGui::ShowMetricsWindow(bool* p_open) { - if (ImGui::Begin("ImGui Metrics", opened)) + if (ImGui::Begin("ImGui Metrics", p_open)) { ImGui::Text("ImGui %s", ImGui::GetVersion()); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); @@ -9415,15 +9416,15 @@ void ImGui::ShowMetricsWindow(bool* opened) { static void NodeDrawList(ImDrawList* draw_list, const char* label) { - bool node_opened = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size); + bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size); if (draw_list == ImGui::GetWindowDrawList()) { ImGui::SameLine(); ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) - if (node_opened) ImGui::TreePop(); + if (node_open) ImGui::TreePop(); return; } - if (!node_opened) + if (!node_open) return; ImDrawList* overlay_draw_list = &GImGui->OverlayDrawList; // Render additional visuals into the top-most draw list @@ -9436,7 +9437,7 @@ void ImGui::ShowMetricsWindow(bool* opened) ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); continue; } - bool draw_opened = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); if (show_clip_rects && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; @@ -9447,7 +9448,7 @@ void ImGui::ShowMetricsWindow(bool* opened) clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255)); vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255)); } - if (!draw_opened) + if (!node_open) continue; for (int i = elem_offset; i+2 < elem_offset + (int)pcmd->ElemCount; i += 3) { @@ -9498,12 +9499,12 @@ void ImGui::ShowMetricsWindow(bool* opened) Funcs::NodeDrawList(g.RenderDrawLists[0][i], "DrawList"); ImGui::TreePop(); } - if (ImGui::TreeNode("Popups", "Opened Popups Stack (%d)", g.OpenedPopupStack.Size)) + if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size)) { - for (int i = 0; i < g.OpenedPopupStack.Size; i++) + for (int i = 0; i < g.OpenPopupStack.Size; i++) { - ImGuiWindow* window = g.OpenedPopupStack[i].Window; - ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenedPopupStack[i].PopupID, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); + ImGuiWindow* window = g.OpenPopupStack[i].Window; + ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupID, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); } ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 5258a5b9..eaf44b9e 100644 --- a/imgui.h +++ b/imgui.h @@ -110,15 +110,15 @@ namespace ImGui IMGUI_API void Shutdown(); IMGUI_API void ShowUserGuide(); // help block IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block - IMGUI_API void ShowTestWindow(bool* opened = NULL); // test window demonstrating ImGui features - IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window for debugging ImGui + IMGUI_API void ShowTestWindow(bool* p_open = NULL); // test window demonstrating ImGui features + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // metrics window for debugging ImGui // Window - IMGUI_API bool Begin(const char* name, bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // push window to the stack and start appending to it. see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). - IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE. this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. - IMGUI_API void End(); // finish appending to current window, pop it off the window stack. - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " + IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // push window to the stack and start appending to it. see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_open' creates a widget on the upper-right to close the window (which sets your bool to false). + IMGUI_API bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE. this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. + IMGUI_API void End(); // finish appending to current window, pop it off the window stack. + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " IMGUI_API void EndChild(); IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() @@ -320,7 +320,7 @@ namespace ImGui IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layout purpose IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); - IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node/collapsing header to be opened. + IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond = 0); // set next TreeNode/CollapsingHeader open state. IMGUI_API float GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags = 0); // return horizontal distance between cursor and text label due to collapsing node. == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header @@ -360,15 +360,15 @@ namespace ImGui // Popups IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). - IMGUI_API bool BeginPopup(const char* str_id); // return true if popup if opened and start outputting to it. only call EndPopup() if BeginPopup() returned true! - IMGUI_API bool BeginPopupModal(const char* name, bool* p_opened = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (can't close them by clicking outside) + IMGUI_API bool BeginPopup(const char* str_id); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true! + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (can't close them by clicking outside) IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item. read comments in .cpp! IMGUI_API bool BeginPopupContextWindow(bool also_over_items = true, const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on current window. IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (no window). IMGUI_API void EndPopup(); IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. - // Logging: all text output from interface is redirected to tty/file/clipboard. Tree nodes are automatically opened. + // Logging: all text output from interface is redirected to tty/file/clipboard. By default, tree nodes are automatically opened during logging. IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard @@ -453,7 +453,7 @@ namespace ImGui static inline bool CollapsingHeader(const char* label, const char* str_id, bool display_frame = true, bool default_open = false) { (void)str_id; (void)display_frame; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ - static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE 1.34+ + static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpen(open, 0); } // OBSOLETE 1.34+ static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+ static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE 1.36+ @@ -528,15 +528,15 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) ImGuiTreeNodeFlags_AllowOverlapMode = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one - ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when opened (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) - ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be opened + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. ImGuiTreeNodeFlags_AlwaysOpen = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). //ImGuiTreeNodeFlags_UnindentArrow = 1 << 9, // FIXME: TODO: Unindent tree so that Label is aligned to current X position //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 10, // FIXME: TODO: Extend hit box horizontally even if not framed - //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 11, // FIXME: TODO: Automatically scroll on TreePop() if node got just opened and contents is not visible + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 11, // FIXME: TODO: Automatically scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 92e883a1..979accc3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -49,15 +49,15 @@ #ifndef IMGUI_DISABLE_TEST_WINDOWS -static void ShowExampleAppConsole(bool* opened); -static void ShowExampleAppLog(bool* opened); -static void ShowExampleAppLayout(bool* opened); -static void ShowExampleAppPropertyEditor(bool* opened); -static void ShowExampleAppLongText(bool* opened); -static void ShowExampleAppAutoResize(bool* opened); -static void ShowExampleAppFixedOverlay(bool* opened); -static void ShowExampleAppManipulatingWindowTitle(bool* opened); -static void ShowExampleAppCustomRendering(bool* opened); +static void ShowExampleAppConsole(bool* p_open); +static void ShowExampleAppLog(bool* p_open); +static void ShowExampleAppLayout(bool* p_open); +static void ShowExampleAppPropertyEditor(bool* p_open); +static void ShowExampleAppLongText(bool* p_open); +static void ShowExampleAppAutoResize(bool* p_open); +static void ShowExampleAppFixedOverlay(bool* p_open); +static void ShowExampleAppManipulatingWindowTitle(bool* p_open); +static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleAppMainMenuBar(); static void ShowExampleMenuFile(); @@ -91,7 +91,7 @@ void ImGui::ShowUserGuide() } // Demonstrate most ImGui features (big function!) -void ImGui::ShowTestWindow(bool* p_opened) +void ImGui::ShowTestWindow(bool* p_open) { // Examples apps static bool show_app_main_menu_bar = false; @@ -150,7 +150,7 @@ void ImGui::ShowTestWindow(bool* p_opened) if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; ImGui::SetNextWindowSize(ImVec2(550,680), ImGuiSetCond_FirstUseEver); - if (!ImGui::Begin("ImGui Demo", p_opened, window_flags)) + if (!ImGui::Begin("ImGui Demo", p_open, window_flags)) { // Early out if the window is collapsed, as an optimization. ImGui::End(); @@ -293,12 +293,12 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; if (i >= 3) node_flags |= ImGuiTreeNodeFlags_AlwaysOpen; - bool opened = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable %s %d", (i >= 3) ? "Leaf" : "Node", i); + bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable %s %d", (i >= 3) ? "Leaf" : "Node", i); if (ImGui::IsItemClicked()) node_clicked = i; - if (opened) + if (node_open) { - ImGui::Text("Blah blah"); + ImGui::Text("Selectable Blah blah"); ImGui::Text("Blah blah"); ImGui::TreePop(); } @@ -1046,9 +1046,9 @@ void ImGui::ShowTestWindow(bool* p_opened) if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data ImGui::AlignFirstTextHeightToWidgets(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). - bool tree_opened = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. + bool node_open = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); - if (tree_opened) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data + if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data // Bullet ImGui::Button("Button##3"); @@ -1437,9 +1437,9 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::TreePop(); } - bool node_opened = ImGui::TreeNode("Tree within single cell"); + bool node_open = ImGui::TreeNode("Tree within single cell"); ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell.\nThere's no storage of state per-cell."); - if (node_opened) + if (node_open) { ImGui::Columns(2, "tree items"); ImGui::Separator(); @@ -1766,9 +1766,9 @@ static void ShowExampleMenuFile() if (ImGui::MenuItem("Quit", "Alt+F4")) {} } -static void ShowExampleAppAutoResize(bool* opened) +static void ShowExampleAppAutoResize(bool* p_open) { - if (!ImGui::Begin("Example: Auto-resizing window", opened, ImGuiWindowFlags_AlwaysAutoResize)) + if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::End(); return; @@ -1782,10 +1782,10 @@ static void ShowExampleAppAutoResize(bool* opened) ImGui::End(); } -static void ShowExampleAppFixedOverlay(bool* opened) +static void ShowExampleAppFixedOverlay(bool* p_open) { ImGui::SetNextWindowPos(ImVec2(10,10)); - if (!ImGui::Begin("Example: Fixed Overlay", opened, ImVec2(0,0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) + if (!ImGui::Begin("Example: Fixed Overlay", p_open, ImVec2(0,0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) { ImGui::End(); return; @@ -1796,9 +1796,9 @@ static void ShowExampleAppFixedOverlay(bool* opened) ImGui::End(); } -static void ShowExampleAppManipulatingWindowTitle(bool* opened) +static void ShowExampleAppManipulatingWindowTitle(bool* p_open) { - (void)opened; + (void)p_open; // By default, Windows are uniquely identified by their title. // You can use the "##" and "###" markers to manipulate the display/ID. Read FAQ at the top of this file! @@ -1823,10 +1823,10 @@ static void ShowExampleAppManipulatingWindowTitle(bool* opened) ImGui::End(); } -static void ShowExampleAppCustomRendering(bool* opened) +static void ShowExampleAppCustomRendering(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(350,560), ImGuiSetCond_FirstUseEver); - if (!ImGui::Begin("Example: Custom rendering", opened)) + if (!ImGui::Begin("Example: Custom rendering", p_open)) { ImGui::End(); return; @@ -1975,10 +1975,10 @@ struct ExampleAppConsole ScrollToBottom = true; } - void Draw(const char* title, bool* opened) + void Draw(const char* title, bool* p_open) { ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); - if (!ImGui::Begin(title, opened)) + if (!ImGui::Begin(title, p_open)) { ImGui::End(); return; @@ -2191,10 +2191,10 @@ struct ExampleAppConsole } }; -static void ShowExampleAppConsole(bool* opened) +static void ShowExampleAppConsole(bool* p_open) { static ExampleAppConsole console; - console.Draw("Example: Console", opened); + console.Draw("Example: Console", p_open); } // Usage: @@ -2223,10 +2223,10 @@ struct ExampleAppLog ScrollToBottom = true; } - void Draw(const char* title, bool* p_opened = NULL) + void Draw(const char* title, bool* p_open = NULL) { ImGui::SetNextWindowSize(ImVec2(500,400), ImGuiSetCond_FirstUseEver); - ImGui::Begin(title, p_opened); + ImGui::Begin(title, p_open); if (ImGui::Button("Clear")) Clear(); ImGui::SameLine(); bool copy = ImGui::Button("Copy"); @@ -2261,7 +2261,7 @@ struct ExampleAppLog } }; -static void ShowExampleAppLog(bool* opened) +static void ShowExampleAppLog(bool* p_open) { static ExampleAppLog log; @@ -2275,19 +2275,19 @@ static void ShowExampleAppLog(bool* opened) last_time = time; } - log.Draw("Example: Log", opened); + log.Draw("Example: Log", p_open); } -static void ShowExampleAppLayout(bool* opened) +static void ShowExampleAppLayout(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiSetCond_FirstUseEver); - if (ImGui::Begin("Example: Layout", opened, ImGuiWindowFlags_MenuBar)) + if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar)) { if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Close")) *opened = false; + if (ImGui::MenuItem("Close")) *p_open = false; ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -2323,10 +2323,10 @@ static void ShowExampleAppLayout(bool* opened) ImGui::End(); } -static void ShowExampleAppPropertyEditor(bool* opened) +static void ShowExampleAppPropertyEditor(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiSetCond_FirstUseEver); - if (!ImGui::Begin("Example: Property editor", opened)) + if (!ImGui::Begin("Example: Property editor", p_open)) { ImGui::End(); return; @@ -2344,12 +2344,12 @@ static void ShowExampleAppPropertyEditor(bool* opened) { ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. ImGui::AlignFirstTextHeightToWidgets(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. - bool is_opened = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); ImGui::NextColumn(); ImGui::AlignFirstTextHeightToWidgets(); ImGui::Text("my sailor is rich"); ImGui::NextColumn(); - if (is_opened) + if (node_open) { static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; for (int i = 0; i < 8; i++) @@ -2395,10 +2395,10 @@ static void ShowExampleAppPropertyEditor(bool* opened) ImGui::End(); } -static void ShowExampleAppLongText(bool* opened) +static void ShowExampleAppLongText(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); - if (!ImGui::Begin("Example: Long text display", opened)) + if (!ImGui::Begin("Example: Long text display", p_open)) { ImGui::End(); return; diff --git a/imgui_internal.h b/imgui_internal.h index 0ef0b847..4027b060 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -381,7 +381,7 @@ struct ImGuiState ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() - ImVector OpenedPopupStack; // Which popups are open (persistent) + ImVector OpenPopupStack; // Which popups are open (persistent) ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) // Storage for SetNexWindow** and SetNextTreeNode*** functions @@ -394,8 +394,8 @@ struct ImGuiState ImGuiSetCond SetNextWindowContentSizeCond; ImGuiSetCond SetNextWindowCollapsedCond; bool SetNextWindowFocus; - bool SetNextTreeNodeOpenedVal; - ImGuiSetCond SetNextTreeNodeOpenedCond; + bool SetNextTreeNodeOpenVal; + ImGuiSetCond SetNextTreeNodeOpenCond; // Render ImDrawData RenderDrawData; // Main ImDrawData instance to pass render information to the user @@ -470,8 +470,8 @@ struct ImGuiState SetNextWindowContentSizeCond = 0; SetNextWindowCollapsedCond = 0; SetNextWindowFocus = false; - SetNextTreeNodeOpenedVal = false; - SetNextTreeNodeOpenedCond = 0; + SetNextTreeNodeOpenVal = false; + SetNextTreeNodeOpenCond = 0; ScalarAsInputTextId = 0; ActiveClickDeltaToCenter = ImVec2(0.0f, 0.0f); @@ -705,7 +705,7 @@ namespace ImGui IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); - IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool opened, float scale = 1.0f, bool shadow = false); + IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. @@ -729,7 +729,7 @@ namespace ImGui IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); - IMGUI_API bool TreeNodeBehaviorIsOpened(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging + IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging IMGUI_API void TreePushRawID(ImGuiID id); IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); From 50df86985d99e20d5a145abb284b83a4b1cb6e7a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 May 2016 10:47:42 +0200 Subject: [PATCH 136/400] Examples: DirectX9: Removed dependency on dx3x9.h so it can be used in a DirectXMath.h only environment (#611) --- examples/directx9_example/imgui_impl_dx9.cpp | 46 +++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 813d58ef..3db8c8c9 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -10,7 +10,7 @@ #include "imgui_impl_dx9.h" // DirectX -#include +#include #define DIRECTINPUT_VERSION 0x0800 #include @@ -26,9 +26,9 @@ static int g_VertexBufferSize = 5000, g_IndexBufferSize = 1 struct CUSTOMVERTEX { - D3DXVECTOR3 pos; - D3DCOLOR col; - D3DXVECTOR2 uv; + float pos[3]; + D3DCOLOR col; + float uv[2]; }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) @@ -37,6 +37,11 @@ struct CUSTOMVERTEX // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) { + // Avoid rendering when minimized + ImGuiIO& io = ImGui::GetIO(); + if (io.DisplaySize.x <= 0.0f || io.DisplaySize.y <= 0.0f) + return; + // Create and grow buffers if needed if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) { @@ -75,12 +80,12 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) const ImDrawVert* vtx_src = &cmd_list->VtxBuffer[0]; for (int i = 0; i < cmd_list->VtxBuffer.size(); i++) { - vtx_dst->pos.x = vtx_src->pos.x; - vtx_dst->pos.y = vtx_src->pos.y; - vtx_dst->pos.z = 0.0f; + vtx_dst->pos[0] = vtx_src->pos.x; + vtx_dst->pos[1] = vtx_src->pos.y; + vtx_dst->pos[2] = 0.0f; vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9 - vtx_dst->uv.x = vtx_src->uv.x; - vtx_dst->uv.y = vtx_src->uv.y; + vtx_dst->uv[0] = vtx_src->uv.x; + vtx_dst->uv[1] = vtx_src->uv.y; vtx_dst++; vtx_src++; } @@ -115,12 +120,21 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); // Setup orthographic projection matrix - D3DXMATRIXA16 mat; - D3DXMatrixIdentity(&mat); - g_pd3dDevice->SetTransform( D3DTS_WORLD, &mat ); - g_pd3dDevice->SetTransform( D3DTS_VIEW, &mat ); - D3DXMatrixOrthoOffCenterLH( &mat, 0.5f, ImGui::GetIO().DisplaySize.x+0.5f, ImGui::GetIO().DisplaySize.y+0.5f, 0.5f, -1.0f, +1.0f ); - g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &mat ); + // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() + { + const float L = 0.5f, R = io.DisplaySize.x+0.5f, T = 0.5f, B = io.DisplaySize.y+0.5f; + D3DMATRIX mat_identity = { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }; + D3DMATRIX mat_projection = + { + 2.0f/(R-L), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f/(T-B), 0.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f, + (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f, + }; + g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); + g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); + g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); + } // Render command lists int vtx_offset = 0; @@ -256,7 +270,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() // Upload texture to graphics system g_FontTexture = NULL; - if (D3DXCreateTexture(g_pd3dDevice, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8B8G8R8, D3DPOOL_DEFAULT, &g_FontTexture) < 0) + if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0) return false; D3DLOCKED_RECT tex_locked_rect; if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK) From 731ff3d3f56e1f4b41cc4a3f02ab03fac6f5d6be Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 May 2016 11:12:59 +0200 Subject: [PATCH 137/400] Examples: DirectX9: Removed dependency on dx3x9 (remainder) (#611) --- examples/directx9_example/build_win32.bat | 2 +- examples/directx9_example/directx9_example.vcxproj | 4 ++-- examples/directx9_example/main.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/directx9_example/build_win32.bat b/examples/directx9_example/build_win32.bat index 08a34756..c3647d4c 100644 --- a/examples/directx9_example/build_win32.bat +++ b/examples/directx9_example/build_win32.bat @@ -1,3 +1,3 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. mkdir Debug -cl /nologo /Zi /MD /I ..\.. /I "%DXSDK_DIR%/Include" /D UNICODE /D _UNICODE *.cpp ..\..\*.cpp /FeDebug/directx9_example.exe /FoDebug/ /link /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d9.lib d3dx9d.lib +cl /nologo /Zi /MD /I ..\.. /I "%DXSDK_DIR%/Include" /D UNICODE /D _UNICODE *.cpp ..\..\*.cpp /FeDebug/directx9_example.exe /FoDebug/ /link /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d9.lib diff --git a/examples/directx9_example/directx9_example.vcxproj b/examples/directx9_example/directx9_example.vcxproj index 83932c55..66a182b5 100644 --- a/examples/directx9_example/directx9_example.vcxproj +++ b/examples/directx9_example/directx9_example.vcxproj @@ -86,7 +86,7 @@ true $(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories) - d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;%(AdditionalDependencies) + d3d9.lib;dxguid.lib;%(AdditionalDependencies) Console @@ -116,7 +116,7 @@ true true $(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories) - d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;%(AdditionalDependencies) + d3d9.lib;dxguid.lib;%(AdditionalDependencies) Console diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 99be4e84..babee5fd 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -3,7 +3,7 @@ #include #include "imgui_impl_dx9.h" -#include +#include #define DIRECTINPUT_VERSION 0x0800 #include #include From f46c91f5ad05ea6f2581bb84c784853dacb4b945 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 May 2016 11:30:43 +0200 Subject: [PATCH 138/400] Examples: DirectX9: Removed dependency on dxguid.lib + remainder of d3dx9.lib (#611) --- examples/directx9_example/directx9_example.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/directx9_example/directx9_example.vcxproj b/examples/directx9_example/directx9_example.vcxproj index 66a182b5..c10731de 100644 --- a/examples/directx9_example/directx9_example.vcxproj +++ b/examples/directx9_example/directx9_example.vcxproj @@ -86,7 +86,7 @@ true $(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories) - d3d9.lib;dxguid.lib;%(AdditionalDependencies) + d3d9.lib;%(AdditionalDependencies) Console @@ -99,7 +99,7 @@ true $(DXSDK_DIR)Lib\x64;%(AdditionalLibraryDirectories) - d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;%(AdditionalDependencies) + d3d9.lib;%(AdditionalDependencies) Console @@ -116,7 +116,7 @@ true true $(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories) - d3d9.lib;dxguid.lib;%(AdditionalDependencies) + d3d9.lib;%(AdditionalDependencies) Console @@ -133,7 +133,7 @@ true true $(DXSDK_DIR)Lib\x64;%(AdditionalLibraryDirectories) - d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;%(AdditionalDependencies) + d3d9.lib;%(AdditionalDependencies) Console From 4ce6cf0512c1dbf22199d238a473a42a6b99712a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 May 2016 20:22:35 +0200 Subject: [PATCH 139/400] Demo: Moved "Fonts" section style editor --- imgui_demo.cpp | 82 +++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 979accc3..2e1fa18f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -217,47 +217,6 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::TreePop(); } - if (ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size)) - { - ImGui::SameLine(); ShowHelpMarker("Tip: Load fonts with io.Fonts->AddFontFromFileTTF()\nbefore calling io.Fonts->GetTex* functions."); - ImFontAtlas* atlas = ImGui::GetIO().Fonts; - if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) - { - ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); - ImGui::TreePop(); - } - ImGui::PushItemWidth(100); - for (int i = 0; i < atlas->Fonts.Size; i++) - { - ImFont* font = atlas->Fonts[i]; - ImGui::BulletText("Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); - ImGui::TreePush((void*)(intptr_t)i); - if (i > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { atlas->Fonts[i] = atlas->Fonts[0]; atlas->Fonts[0] = font; } } - ImGui::PushFont(font); - ImGui::Text("The quick brown fox jumps over the lazy dog"); - ImGui::PopFont(); - if (ImGui::TreeNode("Details")) - { - ImGui::DragFloat("font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this font - ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); - ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); - for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) - { - ImFontConfig* cfg = &font->ConfigData[config_i]; - ImGui::BulletText("Input %d: \'%s\'\nOversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); - } - ImGui::TreePop(); - } - ImGui::TreePop(); - } - static float window_scale = 1.0f; - ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window - ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything - ImGui::PopItemWidth(); - ImGui::SetWindowFontScale(window_scale); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Logging")) { ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded. You can also call ImGui::LogText() to output directly to the log without a visual output."); @@ -1685,6 +1644,47 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::TreePop(); } + if (ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size)) + { + ImGui::SameLine(); ShowHelpMarker("Tip: Load fonts with io.Fonts->AddFontFromFileTTF()\nbefore calling io.Fonts->GetTex* functions."); + ImFontAtlas* atlas = ImGui::GetIO().Fonts; + if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); + ImGui::TreePop(); + } + ImGui::PushItemWidth(100); + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + ImGui::BulletText("Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); + ImGui::TreePush((void*)(intptr_t)i); + if (i > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { atlas->Fonts[i] = atlas->Fonts[0]; atlas->Fonts[0] = font; } } + ImGui::PushFont(font); + ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::PopFont(); + if (ImGui::TreeNode("Details")) + { + ImGui::DragFloat("font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this font + ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + { + ImFontConfig* cfg = &font->ConfigData[config_i]; + ImGui::BulletText("Input %d: \'%s\'\nOversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + static float window_scale = 1.0f; + ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window + ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything + ImGui::PopItemWidth(); + ImGui::SetWindowFontScale(window_scale); + ImGui::TreePop(); + } + ImGui::PopItemWidth(); } From 0058492156fe7651e39694a9e07c5017327f517d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 May 2016 17:20:11 +0200 Subject: [PATCH 140/400] Fonts readme, refering to IconFontCppHeaders, AddRemapChar() function, etc. --- extra_fonts/README.txt | 25 +++++++++++++++++++++---- imgui.cpp | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/extra_fonts/README.txt b/extra_fonts/README.txt index b577b870..1e9bc13c 100644 --- a/extra_fonts/README.txt +++ b/extra_fonts/README.txt @@ -1,9 +1,13 @@ The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' that you can use without any external files. - Those are only provided as a convenience, you can load your own .TTF files. + The files in this folder are only provided as a convenience, you can use any of your own .TTF files. Fonts are rasterized in a single texture at the time of calling either of io.Fonts.GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). + If you want to use icons in ImGui, a good idea is to merge an icon font within your main font, and refer to icons directly in your strings. + You can use headers files with definitions for popular icon fonts codepoints, by Juliette Foucaut, at https://github.com/juliettef/IconFontCppHeaders + + --------------------------------- LOADING INSTRUCTIONS --------------------------------- @@ -35,10 +39,10 @@ Combine two fonts into one: - // Load main font + // Load a first font io.Fonts->AddFontDefault(); - // Add character ranges and merge into main font + // Add character ranges and merge into the previous font // The ranges array is not copied by the AddFont* functions and is used lazily // so ensure it is available for duration of font usage static const ImWchar icons_ranges[] = { 0xf000, 0xf3ff, 0 }; // will not be copied by AddFont* so keep in scope. @@ -63,6 +67,16 @@ ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); font->DisplayOffset.y += 1; // Render 1 pixel down + +--------------------------------- + REMAP CODEPOINTS +--------------------------------- + + All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will not work. + In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. + You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code. + + --------------------------------- EMBED A FONT IN SOURCE CODE --------------------------------- @@ -75,8 +89,9 @@ ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); + --------------------------------- - INCLUDED FONT FILES + FONT FILES INCLUDED IN THIS FOLDER --------------------------------- Cousine-Regular.ttf @@ -102,6 +117,7 @@ Copyright (c) 2012, Jonathan Pinhorn SIL OPEN FONT LICENSE Version 1.1 + --------------------------------- LINKS --------------------------------- @@ -109,6 +125,7 @@ Icon fonts https://fortawesome.github.io/Font-Awesome/ https://github.com/SamBrishes/kenney-icon-font + https://design.google.com/icons/ Typefaces for source code beautification https://github.com/chrissimpkins/codeface diff --git a/imgui.cpp b/imgui.cpp index 70649fdb..b3e9a4b2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -414,7 +414,7 @@ Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. - All strings passed need to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will not work. + All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will not work. In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code. From 9b793276736a63302bc1be7108f583eb604eaf59 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 May 2016 20:22:57 +0200 Subject: [PATCH 141/400] BeginGroup() fixed using within Columns set (fix #630) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index b3e9a4b2..ae0ecd34 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8911,7 +8911,7 @@ void ImGui::BeginGroup() group_data.BackupLogLinePosY = window->DC.LogLinePosY; group_data.AdvanceCursor = true; - window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x; + window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.CurrentLineHeight = 0.0f; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; From efedaa5df37b671e1ebd86aad3f3d6ef7ec1c449 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 May 2016 20:49:17 +0200 Subject: [PATCH 142/400] Updated FAQ (#628) --- README.md | 4 +++- imgui.cpp | 22 ++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 88c7f4e3..3057fd5e 100644 --- a/README.md +++ b/README.md @@ -95,12 +95,14 @@ Frequently Asked Question (FAQ) The library started its life and is best known as "ImGui" only due to the fact that I didn't give it a proper name when I released it. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations. It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "dear imgui" that people can use to refer to this specific library in ambiguous situations. How do I update to a newer version of ImGui? -
Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) +
What is ImTextureID and how do I display an image?
I integrated ImGui in my engine and the text or lines are blurry..
I integrated ImGui in my engine and some elements are disappearing when I move windows around.. +
How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs.
How can I load a different font than the default?
How can I load multiple fonts?
How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? +
How can I use the drawing facilities without an ImGui window? (using ImDrawList API) See the FAQ in imgui.cpp for answers. diff --git a/imgui.cpp b/imgui.cpp index ae0ecd34..518ee0f3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -20,12 +20,13 @@ - How can I help? - How do I update to a newer version of ImGui? - What is ImTextureID and how do I display an image? - - Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) / A primer on the use of labels/IDs in ImGui. - I integrated ImGui in my engine and the text or lines are blurry.. - I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. + - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs. - How can I load a different font than the default? - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? + - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) - ISSUES & TODO-LIST - CODE @@ -278,6 +279,13 @@ ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use. It is your responsibility to get textures uploaded to your GPU. + Q: I integrated ImGui in my engine and the text or lines are blurry.. + A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). + Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. + + Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. + A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height). + Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) A: Yes. A primer on the use of labels/IDs in ImGui.. @@ -371,13 +379,6 @@ e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! - Q: I integrated ImGui in my engine and the text or lines are blurry.. - A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). - Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. - - Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height). - Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) A: Use the font atlas to load the TTF file you want: @@ -424,6 +425,10 @@ As for text input, depends on you passing the right character code to io.AddInputCharacter(). The example applications do that. + Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) + A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag, zero background alpha, + then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. + - tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code. - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug" - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of another window (to get/set other settings) @@ -565,6 +570,7 @@ - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438) - style editor: color child window height expressed in multiple of line height. - remote: make a system like RemoteImGui first-class citizen/project (#75) + - drawlist: move Font, FontSize, FontTexUvWhitePixel inside ImDrawList and make it self-contained (apart from drawing settings?) - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - examples: directx9: save/restore device state more thoroughly. - examples: window minimize, maximize (#583) From 79ad22e1f2e90eee6d07940786ad604fdcab2aea Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 May 2016 23:17:53 +0200 Subject: [PATCH 143/400] Fixed various Clang -Weverything warnings (#626) --- examples/opengl_example/imgui_impl_glfw.cpp | 2 +- examples/sdl_opengl_example/imgui_impl_sdl.cpp | 2 +- imgui.cpp | 12 +++++------- imgui_demo.cpp | 9 ++++++--- imgui_draw.cpp | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index f6447e15..2d1f5c1a 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -101,7 +101,7 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glBindTexture(GL_TEXTURE_2D, last_texture); + glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index 0d885b07..a35dc1ce 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -90,7 +90,7 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glBindTexture(GL_TEXTURE_2D, last_texture); + glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); diff --git a/imgui.cpp b/imgui.cpp index 518ee0f3..153375b9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -603,7 +603,6 @@ #pragma warning (disable: 4127) // condition expression is constant #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen -#define snprintf _snprintf #endif // Clang warnings with -Weverything @@ -615,7 +614,6 @@ #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // #pragma clang diagnostic ignored "-Wmissing-noreturn" // warning : function xx could be declared with attribute 'noreturn' warning // GetDefaultFontData() asserts which some implementation makes it never return. -#pragma clang diagnostic ignored "-Wdeprecated-declarations"// warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' #endif #ifdef __GNUC__ @@ -4815,7 +4813,7 @@ void ImGui::SetNextWindowFocus() ImVec2 ImGui::GetContentRegionMax() { ImGuiWindow* window = GetCurrentWindowRead(); - ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y); + ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x, window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y); ImVec2 mx = content_region_size - window->Scroll - window->WindowPadding; if (window->DC.ColumnsCount != 1) mx.x = ImGui::GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x; @@ -4843,7 +4841,7 @@ ImVec2 ImGui::GetWindowContentRegionMin() ImVec2 ImGui::GetWindowContentRegionMax() { ImGuiWindow* window = GetCurrentWindowRead(); - ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y); + ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y); ImVec2 m = content_region_size - window->Scroll - window->WindowPadding - window->ScrollbarSizes; return m; } @@ -9163,7 +9161,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) window->DC.ColumnsCount = columns_count; window->DC.ColumnsShowBorders = border; - const float content_region_width = window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x; + const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : window->Size.x; window->DC.ColumnsMinX = window->DC.IndentX; // Lock our horizontal range window->DC.ColumnsMaxX = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x; window->DC.ColumnsStartPosY = window->DC.CursorPos.y; @@ -9443,7 +9441,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); continue; } - bool node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); if (show_clip_rects && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; @@ -9454,7 +9452,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255)); vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255)); } - if (!node_open) + if (!pcmd_node_open) continue; for (int i = elem_offset; i+2 < elem_offset + (int)pcmd->ElemCount; i += 3) { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2e1fa18f..afe8e5a3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -25,9 +25,12 @@ #define snprintf _snprintf #endif #ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size @@ -2182,7 +2185,7 @@ struct ExampleAppConsole // A better implementation would preserve the data on the current input line along with cursor position. if (prev_history_pos != HistoryPos) { - data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : ""); + data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, (size_t)data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : ""); data->BufDirty = true; } } @@ -2340,7 +2343,7 @@ static void ShowExampleAppPropertyEditor(bool* p_open) struct funcs { - static void ShowDummyObject(const char* prefix, ImU32 uid) + static void ShowDummyObject(const char* prefix, int uid) { ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. ImGui::AlignFirstTextHeightToWidgets(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. @@ -2357,7 +2360,7 @@ static void ShowExampleAppPropertyEditor(bool* p_open) ImGui::PushID(i); // Use field index as identifier. if (i < 2) { - ShowDummyObject("Child", ImGui::GetID("foo")); + ShowDummyObject("Child", 424242); } else { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index da070b22..4531f8af 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -37,7 +37,7 @@ #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // -//#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used From c1da3e354e031577070b22d677f2e5d9de0813b6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 May 2016 23:20:41 +0200 Subject: [PATCH 144/400] Examples: SDL: Fixed unused variable warning on non-Windows platforms (#626) --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 2 ++ examples/sdl_opengl_example/imgui_impl_sdl.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index c3fed5f0..d97b4cc0 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -330,6 +330,8 @@ bool ImGui_ImplSdlGL3_Init(SDL_Window* window) SDL_VERSION(&wmInfo.version); SDL_GetWindowWMInfo(window, &wmInfo); io.ImeWindowHandle = wmInfo.info.win.window; +#else + (void)window; #endif return true; diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index a35dc1ce..ae42f143 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -218,6 +218,8 @@ bool ImGui_ImplSdl_Init(SDL_Window* window) SDL_VERSION(&wmInfo.version); SDL_GetWindowWMInfo(window, &wmInfo); io.ImeWindowHandle = wmInfo.info.win.window; +#else + (void)window; #endif return true; From f22b6e1e09229161a703e31aef88ce9631b4dd65 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 May 2016 23:28:16 +0200 Subject: [PATCH 145/400] Fixed/silenced various absurd GCC warnings from outer space (#626) --- imgui.cpp | 4 ++-- imgui_draw.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 153375b9..ae44ef98 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -613,12 +613,12 @@ #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // -#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning : function xx could be declared with attribute 'noreturn' warning // GetDefaultFontData() asserts which some implementation makes it never return. -#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' // #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' #endif //------------------------------------------------------------------------- diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4531f8af..8bfdaa78 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -58,7 +58,7 @@ namespace IMGUI_STB_NAMESPACE #ifdef _MSC_VER #pragma warning (push) -#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration #endif #ifdef __clang__ @@ -68,6 +68,11 @@ namespace IMGUI_STB_NAMESPACE #pragma clang diagnostic ignored "-Wmissing-prototypes" #endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] +#endif + #define STBRP_ASSERT(x) IM_ASSERT(x) #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION #define STBRP_STATIC @@ -86,6 +91,10 @@ namespace IMGUI_STB_NAMESPACE #endif #include "stb_truetype.h" +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + #ifdef __clang__ #pragma clang diagnostic pop #endif From 67df0ba18543dfaadd4eadd44e23522b398676cd Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 May 2016 09:18:07 +0200 Subject: [PATCH 146/400] Updated FAQ and Readme with more prominent info about WantCaptureMouse etc. flags (#635) --- README.md | 1 + imgui.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3057fd5e..9e32e9e2 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ The library started its life and is best known as "ImGui" only due to the fact t
I integrated ImGui in my engine and the text or lines are blurry..
I integrated ImGui in my engine and some elements are disappearing when I move windows around..
How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs. +
How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
How can I load a different font than the default?
How can I load multiple fonts?
How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? diff --git a/imgui.cpp b/imgui.cpp index ae44ef98..79969ebd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -23,6 +23,7 @@ - I integrated ImGui in my engine and the text or lines are blurry.. - I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs. + - How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application? - How can I load a different font than the default? - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? @@ -141,9 +142,8 @@ SwapBuffers(); } - - after calling ImGui::NewFrame() you can read back flags from the IO structure to tell how ImGui intends to use your inputs. - When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application. - When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available. + - You can read back 'io.WantCaptureMouse', 'io.WantCaptureKeybord' etc. flags from the IO structure to tell how ImGui intends to use your + inputs and to know if you should share them or hide them from the rest of your application. Read the FAQ below for more information. API BREAKING CHANGES @@ -379,6 +379,12 @@ e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! + Q: How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application? + A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame. + When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application. + When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available. + ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is a more accurate and complete than testing for ImGui::IsMouseHoveringAnyWindow(). + Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) A: Use the font atlas to load the TTF file you want: From 313d388bba42e0634a02b976dcdbae238d25eddc Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 May 2016 11:31:32 +0200 Subject: [PATCH 147/400] Reorganised windows moving code, documented a lag in FindHoveredWindow(), fixing lag whole moving windows (#635) --- imgui.cpp | 69 ++++++++++++++++++++++++++---------------------- imgui_internal.h | 6 +++-- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 79969ebd..613e8db6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2007,8 +2007,35 @@ void ImGui::NewFrame() g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdIsAlive = false; g.ActiveIdIsJustActivated = false; - if (!g.ActiveId) + + // Handle user moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. + if (g.MovedWindowMoveId && g.MovedWindowMoveId == g.ActiveId) + { + KeepAliveID(g.MovedWindowMoveId); + IM_ASSERT(g.MovedWindow && g.MovedWindow->RootWindow); + IM_ASSERT(g.MovedWindow->RootWindow->MoveID == g.MovedWindowMoveId); + if (g.IO.MouseDown[0]) + { + if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoMove)) + { + g.MovedWindow->PosFloat += g.IO.MouseDelta; + if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoSavedSettings)) + MarkSettingsDirty(); + } + FocusWindow(g.MovedWindow); + } + else + { + SetActiveID(0); + g.MovedWindow = NULL; + g.MovedWindowMoveId = 0; + } + } + else + { g.MovedWindow = NULL; + g.MovedWindowMoveId = 0; + } // Delay saving settings so we don't spam disk too much if (g.SettingsDirtyTimer > 0.0f) @@ -2019,11 +2046,11 @@ void ImGui::NewFrame() } // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow - g.HoveredWindow = FindHoveredWindow(g.IO.MousePos, false); + g.HoveredWindow = g.MovedWindow ? g.MovedWindow : FindHoveredWindow(g.IO.MousePos, false); if (g.HoveredWindow && (g.HoveredWindow->Flags & ImGuiWindowFlags_ChildWindow)) g.HoveredRootWindow = g.HoveredWindow->RootWindow; else - g.HoveredRootWindow = FindHoveredWindow(g.IO.MousePos, true); + g.HoveredRootWindow = g.MovedWindow ? g.MovedWindow->RootWindow : FindHoveredWindow(g.IO.MousePos, true); if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow()) { @@ -2420,8 +2447,6 @@ void ImGui::EndFrame() ImGui::End(); // Click to focus window and start moving (after we're done with all our widgets) - if (!g.ActiveId) - g.MovedWindow = NULL; if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0]) { if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear @@ -2432,7 +2457,8 @@ void ImGui::EndFrame() if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) { g.MovedWindow = g.HoveredWindow; - SetActiveID(g.HoveredRootWindow->MoveID, g.HoveredRootWindow); + g.MovedWindowMoveId = g.HoveredRootWindow->MoveID; + SetActiveID(g.MovedWindowMoveId, g.HoveredRootWindow); } } else if (g.FocusedWindow != NULL && GetFrontMostModalRootWindow() == NULL) @@ -2842,6 +2868,7 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items } // Find window given position, search front-to-back +// FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected. static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) { ImGuiState& g = *GImGui; @@ -2856,7 +2883,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) continue; // Using the clipped AABB so a child window will typically be clipped by its parent. - ImRect bb(window->ClippedWindowRect.Min - g.Style.TouchExtraPadding, window->ClippedWindowRect.Max + g.Style.TouchExtraPadding); + ImRect bb(window->WindowRectClipped.Min - g.Style.TouchExtraPadding, window->WindowRectClipped.Max + g.Style.TouchExtraPadding); if (bb.Contains(pos)) return window; } @@ -3884,28 +3911,6 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->PosFloat = g.IO.MousePos + ImVec2(2,2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. } - // User moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. - KeepAliveID(window->MoveID); - if (g.ActiveId == window->MoveID) - { - if (g.IO.MouseDown[0]) - { - if (!(flags & ImGuiWindowFlags_NoMove)) - { - window->PosFloat += g.IO.MouseDelta; - if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); - } - IM_ASSERT(g.MovedWindow != NULL); - FocusWindow(g.MovedWindow); - } - else - { - SetActiveID(0); - g.MovedWindow = NULL; // Not strictly necessary but doing it for sanity. - } - } - // Clamp position so it stays visible if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) { @@ -4120,8 +4125,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() - window->ClippedWindowRect = window->Rect(); - window->ClippedWindowRect.Clip(window->ClipRect); + window->WindowRectClipped = window->Rect(); + window->WindowRectClipped.Clip(window->ClipRect); // Pressing CTRL+C while holding on a window copy its content to the clipboard // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. @@ -4158,7 +4163,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->Collapsed = parent_window && parent_window->Collapsed; if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) - window->Collapsed |= (window->ClippedWindowRect.Min.x >= window->ClippedWindowRect.Max.x || window->ClippedWindowRect.Min.y >= window->ClippedWindowRect.Max.y); + window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y); // 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 simpler at this point) diff --git a/imgui_internal.h b/imgui_internal.h index 4027b060..6c72a051 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -375,7 +375,8 @@ struct ImGuiState bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Set only by active widget ImGuiWindow* ActiveIdWindow; - ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Pointer is only valid if ActiveID is the "#MOVE" identifier of a window. + ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. + ImGuiID MovedWindowMoveId; // == MovedWindow->RootWindow->MoveId ImVector Settings; // .ini Settings float SettingsDirtyTimer; // Save .ini settinngs on disk when time reaches zero ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() @@ -460,6 +461,7 @@ struct ImGuiState ActiveIdAllowOverlap = false; ActiveIdWindow = NULL; MovedWindow = NULL; + MovedWindowMoveId = 0; SettingsDirtyTimer = 0.0f; SetNextWindowPosVal = ImVec2(0.0f, 0.0f); @@ -627,7 +629,7 @@ struct IMGUI_API ImGuiWindow ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack ImRect ClipRect; // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. - ImRect ClippedWindowRect; // = ClipRect just after setup in Begin() + ImRect WindowRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. int LastFrameActive; float ItemWidthDefault; ImGuiSimpleColumns MenuColumns; // Simplified columns storage for menu items From ce4d731486b379c5a4fc6e5d4f54f3a2256e16b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 18:10:32 +0200 Subject: [PATCH 148/400] Minor comments, tweaks --- imgui.h | 7 ++++--- imgui_demo.cpp | 2 ++ imgui_internal.h | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index eaf44b9e..2a7199c9 100644 --- a/imgui.h +++ b/imgui.h @@ -158,7 +158,7 @@ namespace ImGui IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] IMGUI_API void SetScrollHere(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions. - IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget + IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use negative 'offset' to access previous widgets. IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it) IMGUI_API ImGuiStorage* GetStateStorage(); @@ -948,7 +948,7 @@ struct ImGuiTextBuffer IMGUI_API void appendv(const char* fmt, va_list args); }; -// Helper: Key->value storage +// Helper: Simple Key->value storage // - Store collapse state for a tree (Int 0/1) // - Store color edit options (Int using values in ImGuiColorEditMode enum). // - Custom user storage for temporary values. @@ -956,6 +956,7 @@ struct ImGuiTextBuffer // Declare your own storage if: // - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). // - You want to store custom debug data easily without adding or editing structures in your code. +// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. struct ImGuiStorage { struct Pair @@ -970,7 +971,7 @@ struct ImGuiStorage // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) // - Set***() functions find pair, insertion on demand if missing. - // - Sorted insertion is costly but should amortize. A typical frame shouldn't need to insert any new pair. + // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. IMGUI_API void Clear(); IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; IMGUI_API void SetInt(ImGuiID key, int val); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index afe8e5a3..894f4676 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1030,9 +1030,11 @@ void ImGui::ShowTestWindow(bool* p_open) static bool track = true; static int track_line = 50, scroll_to_px = 200; ImGui::Checkbox("Track", &track); + ImGui::PushItemWidth(100); ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line %.0f"); bool scroll_to = ImGui::Button("Scroll To"); ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "y = %.0f px"); + ImGui::PopItemWidth(); if (scroll_to) track = false; for (int i = 0; i < 5; i++) diff --git a/imgui_internal.h b/imgui_internal.h index 6c72a051..0b31fa32 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -378,7 +378,7 @@ struct ImGuiState ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. ImGuiID MovedWindowMoveId; // == MovedWindow->RootWindow->MoveId ImVector Settings; // .ini Settings - float SettingsDirtyTimer; // Save .ini settinngs on disk when time reaches zero + float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() @@ -417,7 +417,7 @@ struct ImGuiState float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio float DragSpeedScaleSlow; float DragSpeedScaleFast; - ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? + ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? char Tooltip[1024]; char* PrivateClipboard; // If no custom clipboard handler is defined ImVec2 OsImePosRequest, OsImePosSet; // Cursor position request & last passed to the OS Input Method Editor From 69cc00f91fa440476453ab30d2597481f6b96c6d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 18:18:37 +0200 Subject: [PATCH 149/400] ImGuiStorage: Added bool helper functions for completeness. --- imgui.cpp | 15 +++++++++++++++ imgui.h | 5 ++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 613e8db6..b982a71e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1313,6 +1313,11 @@ int ImGuiStorage::GetInt(ImU32 key, int default_val) const return it->val_i; } +bool ImGuiStorage::GetBool(ImU32 key, bool default_val) const +{ + return GetInt(key, default_val ? 1 : 0) != 0; +} + float ImGuiStorage::GetFloat(ImU32 key, float default_val) const { ImVector::iterator it = LowerBound(const_cast&>(Data), key); @@ -1338,6 +1343,11 @@ int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) return &it->val_i; } +bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) +{ + return (bool*)GetIntRef(key, default_val ? 1 : 0); +} + float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) { ImVector::iterator it = LowerBound(Data, key); @@ -1366,6 +1376,11 @@ void ImGuiStorage::SetInt(ImU32 key, int val) it->val_i = val; } +void ImGuiStorage::SetBool(ImU32 key, bool val) +{ + SetInt(key, val ? 1 : 0); +} + void ImGuiStorage::SetFloat(ImU32 key, float val) { ImVector::iterator it = LowerBound(Data, key); diff --git a/imgui.h b/imgui.h index 2a7199c9..2683308c 100644 --- a/imgui.h +++ b/imgui.h @@ -975,6 +975,8 @@ struct ImGuiStorage IMGUI_API void Clear(); IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; IMGUI_API void SetInt(ImGuiID key, int val); + IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; + IMGUI_API void SetBool(ImGuiID key, bool val); IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; IMGUI_API void SetFloat(ImGuiID key, float val); IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL @@ -986,7 +988,8 @@ struct ImGuiStorage // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; // - You can also use this to quickly create temporary editable values during a session of using Edit&Continue, without restarting your application. IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); - IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0); + IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); + IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); // Use on your own storage if you know only integer are being stored (open/close all tree nodes) From 6e8579fc144f1d59a75aabf3740470d3e3739a1b Mon Sep 17 00:00:00 2001 From: Sergej Reich Date: Sat, 7 May 2016 17:57:13 +0200 Subject: [PATCH 150/400] Ignore implicit conversion warnings --- imgui.cpp | 2 ++ imgui_demo.cpp | 2 ++ imgui_draw.cpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index b982a71e..dffa1356 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -625,6 +625,8 @@ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #endif //------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 894f4676..c19e2b5b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -35,6 +35,8 @@ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #endif // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8bfdaa78..5fcdc83c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -41,6 +41,8 @@ #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #endif //------------------------------------------------------------------------- From 5fe2cacd4da495be9b656b29d6e2e848434f447a Mon Sep 17 00:00:00 2001 From: josiahmanson Date: Sat, 7 May 2016 10:42:48 -0700 Subject: [PATCH 151/400] DX11 example depth test --- .../directx11_example/imgui_impl_dx11.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 5f209bc0..33afb7ea 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -35,6 +35,7 @@ static ID3D11ShaderResourceView*g_pFontTextureView = NULL; static ID3D11RasterizerState* g_pRasterizerState = NULL; static ID3D11BlendState* g_pBlendState = NULL; static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000; +static ID3D11DepthStencilState* g_pDSState = NULL; struct VERTEX_CONSTANT_BUFFER { @@ -138,6 +139,8 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; DXGI_FORMAT IndexBufferFormat; ID3D11InputLayout* InputLayout; + ID3D11DepthStencilState* DepthStencilState; + UINT StencilRef; }; BACKUP_DX11_STATE old; old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; @@ -155,6 +158,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); ctx->IAGetInputLayout(&old.InputLayout); + ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); // Setup viewport D3D11_VIEWPORT vp; @@ -182,6 +186,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); ctx->RSSetState(g_pRasterizerState); + ctx->OMSetDepthStencilState( g_pDSState, 1 ); // Render command lists int vtx_offset = 0; @@ -224,6 +229,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); + ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); } IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) @@ -448,6 +454,18 @@ bool ImGui_ImplDX11_CreateDeviceObjects() g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState); } + + // Create Depth-Stencil State + { + D3D11_DEPTH_STENCIL_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.StencilEnable = false; + desc.DepthEnable = true; + desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + desc.DepthFunc = D3D11_COMPARISON_ALWAYS; + g_pd3dDevice->CreateDepthStencilState( &desc, &g_pDSState ); + } + ImGui_ImplDX11_CreateFontsTexture(); return true; @@ -471,6 +489,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; } if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; } if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; } + if (g_pDSState) { g_pDSState->Release(); g_pDSState = NULL; } } bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context) From 8b428e8c74c013bd84cf4284e69192c0e222a4c9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 19:54:27 +0200 Subject: [PATCH 152/400] Added CreateContext/DestroyContext/GetCurrentContext/SetCurrentContext() (#586, #269) --- imgui.cpp | 35 ++++++++++++++++++++++++----------- imgui.h | 10 ++++++---- imgui_draw.cpp | 4 ++-- imgui_internal.h | 13 ++++++------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b982a71e..fe1fde54 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -153,6 +153,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. @@ -694,12 +695,12 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); //----------------------------------------------------------------------------- // We access everything through this pointer (always assumed to be != NULL) -// You can swap the pointer to a different context by calling ImGui::SetInternalState() -static ImGuiState GImDefaultState; -ImGuiState* GImGui = &GImDefaultState; +// You can swap the pointer to a different context by calling ImGui::SetCurrentContext() +static ImGuiState GImDefaultContext; +ImGuiState* GImGui = &GImDefaultContext; // Statically allocated default font atlas. This is merely a maneuver to keep ImFontAtlas definition at the bottom of the .h file (otherwise it'd be inside ImGuiIO) -// Also we wouldn't be able to new() one at this point, before users may define IO.MemAllocFn. +// Also we wouldn't be able to new() one at this point, before users have a chance to setup their allocator. static ImFontAtlas GImDefaultFontAtlas; //----------------------------------------------------------------------------- @@ -1888,21 +1889,33 @@ const char* ImGui::GetVersion() // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself // Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module -void* ImGui::GetInternalState() +ImGuiState* ImGui::GetCurrentContext() { return GImGui; } -size_t ImGui::GetInternalStateSize() +void ImGui::SetCurrentContext(ImGuiState* ctx) { - return sizeof(ImGuiState); + GImGui = ctx; } -void ImGui::SetInternalState(void* state, bool construct) +ImGuiState* ImGui::CreateContext(void* (*malloc_fn)(size_t), void (*free_fn)(void*)) { - if (construct) - IM_PLACEMENT_NEW(state) ImGuiState(); - GImGui = (ImGuiState*)state; + if (!malloc_fn) malloc_fn = malloc; + ImGuiState* ctx = (ImGuiState*)malloc_fn(sizeof(ImGuiState)); + IM_PLACEMENT_NEW(ctx) ImGuiState(); + ctx->IO.MemAllocFn = malloc_fn; + ctx->IO.MemFreeFn = free_fn ? free_fn : free; + return ctx; +} + +void ImGui::DestroyContext(ImGuiState* ctx) +{ + void (*free_fn)(void*) = ctx->IO.MemFreeFn; + ctx->~ImGuiState(); + free_fn(ctx); + if (GImGui == ctx) + GImGui = NULL; } ImGuiIO& ImGui::GetIO() diff --git a/imgui.h b/imgui.h index 2683308c..d5479803 100644 --- a/imgui.h +++ b/imgui.h @@ -54,6 +54,7 @@ struct ImGuiTextFilter; // Parse and apply text filters. In format " struct ImGuiTextBuffer; // Text buffer for logging/accumulating text struct ImGuiTextEditCallbackData; // Shared state of ImGui::InputText() when using custom callbacks (advanced) struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiState; // ImGui context (opaque) // Enumerations (declared as int for compatibility and to not pollute the top of this file) typedef unsigned int ImU32; @@ -442,11 +443,12 @@ namespace ImGui IMGUI_API const char* GetClipboardText(); IMGUI_API void SetClipboardText(const char* text); - // Internal state/context access - if you want to use multiple ImGui context, or share context between modules (e.g. DLL), or allocate the memory yourself + // Internal context access - if you want to use multiple context, share context between modules (e.g. DLL). There is a default context created and active by default. IMGUI_API const char* GetVersion(); - IMGUI_API void* GetInternalState(); - IMGUI_API size_t GetInternalStateSize(); - IMGUI_API void SetInternalState(void* state, bool construct = false); + IMGUI_API ImGuiState* CreateContext(void* (*malloc_fn)(size_t) = NULL, void (*free_fn)(void*) = NULL); + IMGUI_API void DestroyContext(ImGuiState* ctx); + IMGUI_API ImGuiState* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiState* ctx); // Obsolete (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8bfdaa78..007e48ee 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -245,7 +245,7 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_ void ImDrawList::PushClipRectFullScreen() { PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w)); - //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiState from here? + //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiContext from here? } void ImDrawList::PopClipRect() @@ -1665,7 +1665,7 @@ ImFont::~ImFont() // If you want to delete fonts you need to do it between Render() and NewFrame(). // FIXME-CLEANUP /* - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.Font == this) g.Font = NULL; */ diff --git a/imgui_internal.h b/imgui_internal.h index 0b31fa32..4eee4f7d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -33,7 +33,6 @@ struct ImGuiTextEditState; struct ImGuiIniData; struct ImGuiMouseCursorData; struct ImGuiPopupRef; -struct ImGuiState; struct ImGuiWindow; typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ @@ -71,7 +70,7 @@ namespace ImGuiStb // Context //----------------------------------------------------------------------------- -extern IMGUI_API ImGuiState* GImGui; +extern IMGUI_API ImGuiState* GImGui; // current implicit ImGui context pointer //----------------------------------------------------------------------------- // Helpers @@ -144,7 +143,7 @@ static inline ImVec2 ImFloor(ImVec2 v) struct ImPlacementNewDummy {}; inline void* operator new(size_t, ImPlacementNewDummy, void* ptr) { return ptr; } inline void operator delete(void*, ImPlacementNewDummy, void*) {} -#define IM_PLACEMENT_NEW(_PTR) new(ImPlacementNewDummy() ,_PTR) +#define IM_PLACEMENT_NEW(_PTR) new(ImPlacementNewDummy(), _PTR) #endif //----------------------------------------------------------------------------- @@ -274,7 +273,7 @@ struct ImGuiColumnData //float IndentX; }; -// Simple column measurement currently used for MenuItem() only. This is very short-sighted for now and NOT a generic helper. +// Simple column measurement currently used for MenuItem() only. This is very short-sighted/throw-away code and NOT a generic helper. struct IMGUI_API ImGuiSimpleColumns { int Count; @@ -283,9 +282,9 @@ struct IMGUI_API ImGuiSimpleColumns float Pos[8], NextWidths[8]; ImGuiSimpleColumns(); - void Update(int count, float spacing, bool clear); - float DeclColumns(float w0, float w1, float w2); - float CalcExtraSpace(float avail_w); + void Update(int count, float spacing, bool clear); + float DeclColumns(float w0, float w1, float w2); + float CalcExtraSpace(float avail_w); }; // Internal state of the currently focused/edited text input box From 7b9c0a5c3fb8147699cdbc39b5dae04c55c8f9cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 19:55:51 +0200 Subject: [PATCH 153/400] Renamed ImGuiState -> ImGuiContext (#586, #269) --- imgui.cpp | 320 +++++++++++++++++++++++------------------------ imgui.h | 10 +- imgui_internal.h | 10 +- 3 files changed, 170 insertions(+), 170 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fe1fde54..3dfa7cff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -696,8 +696,8 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); // We access everything through this pointer (always assumed to be != NULL) // You can swap the pointer to a different context by calling ImGui::SetCurrentContext() -static ImGuiState GImDefaultContext; -ImGuiState* GImGui = &GImDefaultContext; +static ImGuiContext GImDefaultContext; +ImGuiContext* GImGui = &GImDefaultContext; // Statically allocated default font atlas. This is merely a maneuver to keep ImFontAtlas definition at the bottom of the .h file (otherwise it'd be inside ImGuiIO) // Also we wouldn't be able to new() one at this point, before users have a chance to setup their allocator. @@ -1677,7 +1677,7 @@ ImGuiID ImGuiWindow::GetID(const void* ptr) static void SetCurrentWindow(ImGuiWindow* window) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.CurrentWindow = window; if (window) g.FontSize = window->CalcFontSize(); @@ -1685,14 +1685,14 @@ static void SetCurrentWindow(ImGuiWindow* window) ImGuiWindow* ImGui::GetParentWindow() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(g.CurrentWindowStack.Size >= 2); return g.CurrentWindowStack[(unsigned int)g.CurrentWindowStack.Size - 2]; } void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.ActiveId = id; g.ActiveIdAllowOverlap = false; g.ActiveIdIsJustActivated = true; @@ -1701,14 +1701,14 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) void ImGui::SetHoveredID(ImGuiID id) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.HoveredId = id; g.HoveredIdAllowOverlap = false; } void ImGui::KeepAliveID(ImGuiID id) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.ActiveId == id) g.ActiveIdIsAlive = true; } @@ -1721,7 +1721,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y) return; // Always align ourselves on pixel boundaries - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); @@ -1754,7 +1754,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) return false; // This is a sensible default, but widgets are free to override it after calling ItemAdd() - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (IsMouseHoveringRect(bb.Min, bb.Max)) { // Matching the behavior of IsHovered() but allow if ActiveId==window->MoveID (we clicked on the window background) @@ -1771,7 +1771,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when_logged) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindowRead(); if (!bb.Overlaps(window->ClipRect)) @@ -1784,7 +1784,7 @@ bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when // NB: This is an internal helper. The user-facing IsItemHovered() is using data emitted from ItemAdd(), with a slightly different logic. bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.HoveredId == 0 || g.HoveredId == id || g.HoveredIdAllowOverlap) { ImGuiWindow* window = GetCurrentWindowRead(); @@ -1798,7 +1798,7 @@ bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs) bool ImGui::FocusableItemRegister(ImGuiWindow* window, bool is_active, bool tab_stop) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus; window->FocusIdxAllCounter++; @@ -1831,7 +1831,7 @@ void ImGui::FocusableItemUnregister(ImGuiWindow* window) ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImVec2 content_max; if (size.x < 0.0f || size.y < 0.0f) content_max = g.CurrentWindow->Pos + ImGui::GetContentRegionMax(); @@ -1889,30 +1889,30 @@ const char* ImGui::GetVersion() // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself // Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module -ImGuiState* ImGui::GetCurrentContext() +ImGuiContext* ImGui::GetCurrentContext() { return GImGui; } -void ImGui::SetCurrentContext(ImGuiState* ctx) +void ImGui::SetCurrentContext(ImGuiContext* ctx) { GImGui = ctx; } -ImGuiState* ImGui::CreateContext(void* (*malloc_fn)(size_t), void (*free_fn)(void*)) +ImGuiContext* ImGui::CreateContext(void* (*malloc_fn)(size_t), void (*free_fn)(void*)) { if (!malloc_fn) malloc_fn = malloc; - ImGuiState* ctx = (ImGuiState*)malloc_fn(sizeof(ImGuiState)); - IM_PLACEMENT_NEW(ctx) ImGuiState(); + ImGuiContext* ctx = (ImGuiContext*)malloc_fn(sizeof(ImGuiContext)); + IM_PLACEMENT_NEW(ctx) ImGuiContext(); ctx->IO.MemAllocFn = malloc_fn; ctx->IO.MemFreeFn = free_fn ? free_fn : free; return ctx; } -void ImGui::DestroyContext(ImGuiState* ctx) +void ImGui::DestroyContext(ImGuiContext* ctx) { void (*free_fn)(void*) = ctx->IO.MemFreeFn; - ctx->~ImGuiState(); + ctx->~ImGuiContext(); free_fn(ctx); if (GImGui == ctx) GImGui = NULL; @@ -1946,7 +1946,7 @@ int ImGui::GetFrameCount() void ImGui::NewFrame() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; // Check user data IM_ASSERT(g.IO.DeltaTime >= 0.0f); // Need a positive DeltaTime (zero is tolerated but will cause some timing issues) @@ -2178,7 +2178,7 @@ void ImGui::NewFrame() // NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations. void ImGui::Shutdown() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) if (g.IO.Fonts) // Testing for NULL to allow user to NULLify in case of running Shutdown() on multiple contexts. Bit hacky. @@ -2238,7 +2238,7 @@ void ImGui::Shutdown() static ImGuiIniData* FindWindowSettings(const char* name) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiID id = ImHash(name, 0); for (int i = 0; i != g.Settings.Size; i++) { @@ -2265,7 +2265,7 @@ static ImGuiIniData* AddWindowSettings(const char* name) // FIXME: Write something less rubbish static void LoadSettings() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const char* filename = g.IO.IniFilename; if (!filename) return; @@ -2311,7 +2311,7 @@ static void LoadSettings() static void SaveSettings() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const char* filename = g.IO.IniFilename; if (!filename) return; @@ -2353,7 +2353,7 @@ static void SaveSettings() static void MarkSettingsDirty() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.SettingsDirtyTimer <= 0.0f) g.SettingsDirtyTimer = g.IO.IniSavingRate; } @@ -2449,7 +2449,7 @@ void ImGui::PopClipRect() // This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. void ImGui::EndFrame() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame() IM_ASSERT(g.FrameCountEnded != g.FrameCount); // ImGui::EndFrame() called multiple times, or forgot to call ImGui::NewFrame() again @@ -2520,7 +2520,7 @@ void ImGui::EndFrame() void ImGui::Render() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame() if (g.FrameCountEnded != g.FrameCount) @@ -2610,7 +2610,7 @@ const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) // Pass text data straight to log (without being displayed) void ImGui::LogText(const char* fmt, ...) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (!g.LogEnabled) return; @@ -2631,7 +2631,7 @@ void ImGui::LogText(const char* fmt, ...) // We split text into individual lines to add current tree level padding static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* text_end) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindowRead(); if (!text_end) @@ -2682,7 +2682,7 @@ static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); // Hide anything after a '##' string @@ -2709,7 +2709,7 @@ void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (!text_end) @@ -2733,7 +2733,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons if (text_len == 0) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); // Perform CPU side clipping for single clipped element to avoid using scissor state @@ -2779,7 +2779,7 @@ void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, // Render a triangle to denote expanded/collapsed state void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale, bool shadow) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); const float h = g.FontSize * 1.00f; @@ -2814,7 +2814,7 @@ void ImGui::RenderBullet(ImVec2 pos) void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); ImVec2 a, b, c; @@ -2837,7 +2837,7 @@ void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col) // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize) ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const char* text_display_end; if (hide_text_after_double_hash) @@ -2876,7 +2876,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex // } void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindowRead(); if (g.LogEnabled) { @@ -2899,7 +2899,7 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items // FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected. static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; for (int i = g.Windows.Size-1; i >= 0; i--) { ImGuiWindow* window = g.Windows[i]; @@ -2923,7 +2923,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindowRead(); // Clip @@ -2938,13 +2938,13 @@ bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool c bool ImGui::IsMouseHoveringWindow() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.HoveredWindow == g.CurrentWindow; } bool ImGui::IsMouseHoveringAnyWindow() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.HoveredWindow != NULL; } @@ -2974,7 +2974,7 @@ bool ImGui::IsKeyDown(int key_index) bool ImGui::IsKeyPressed(int key_index, bool repeat) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (key_index < 0) return false; IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); const float t = g.IO.KeysDownDuration[key_index]; @@ -2992,7 +2992,7 @@ bool ImGui::IsKeyPressed(int key_index, bool repeat) bool ImGui::IsKeyReleased(int key_index) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (key_index < 0) return false; IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); if (g.IO.KeysDownDurationPrev[key_index] >= 0.0f && !g.IO.KeysDown[key_index]) @@ -3002,14 +3002,14 @@ bool ImGui::IsKeyReleased(int key_index) bool ImGui::IsMouseDown(int button) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); return g.IO.MouseDown[button]; } bool ImGui::IsMouseClicked(int button, bool repeat) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); const float t = g.IO.MouseDownDuration[button]; if (t == 0.0f) @@ -3027,21 +3027,21 @@ bool ImGui::IsMouseClicked(int button, bool repeat) bool ImGui::IsMouseReleased(int button) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); return g.IO.MouseReleased[button]; } bool ImGui::IsMouseDoubleClicked(int button) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); return g.IO.MouseDoubleClicked[button]; } bool ImGui::IsMouseDragging(int button, float lock_threshold) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); if (!g.IO.MouseDown[button]) return false; @@ -3058,7 +3058,7 @@ ImVec2 ImGui::GetMousePos() // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.CurrentPopupStack.Size > 0) return g.OpenPopupStack[g.CurrentPopupStack.Size-1].MousePosOnOpen; return g.IO.MousePos; @@ -3066,7 +3066,7 @@ ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); if (lock_threshold < 0.0f) lock_threshold = g.IO.MouseDragThreshold; @@ -3078,7 +3078,7 @@ ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) void ImGui::ResetMouseDragDelta(int button) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr g.IO.MouseClickedPos[button] = g.IO.MousePos; @@ -3118,7 +3118,7 @@ bool ImGui::IsItemHoveredRect() bool ImGui::IsItemActive() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.ActiveId) { ImGuiWindow* window = GetCurrentWindowRead(); @@ -3152,7 +3152,7 @@ bool ImGui::IsItemVisible() // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. void ImGui::SetItemAllowOverlap() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.HoveredId == g.CurrentWindow->DC.LastItemID) g.HoveredIdAllowOverlap = true; if (g.ActiveId == g.CurrentWindow->DC.LastItemID) @@ -3188,7 +3188,7 @@ ImVec2 ImGui::CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge, float ou // Tooltip is stored and turned into a BeginTooltip()/EndTooltip() sequence at the end of the frame. Each call override previous value. void ImGui::SetTooltipV(const char* fmt, va_list args) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImFormatStringV(g.Tooltip, IM_ARRAYSIZE(g.Tooltip), fmt, args); } @@ -3202,7 +3202,7 @@ void ImGui::SetTooltip(const char* fmt, ...) static ImRect GetVisibleRect() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) return ImRect(g.IO.DisplayVisibleMin, g.IO.DisplayVisibleMax); return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); @@ -3222,7 +3222,7 @@ void ImGui::EndTooltip() static bool IsPopupOpen(ImGuiID id) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const bool is_open = g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupID == id; return is_open; } @@ -3233,7 +3233,7 @@ static bool IsPopupOpen(ImGuiID id) // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) void ImGui::OpenPopupEx(const char* str_id, bool reopen_existing) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiID id = window->GetID(str_id); int current_stack_size = g.CurrentPopupStack.Size; @@ -3254,7 +3254,7 @@ void ImGui::OpenPopup(const char* str_id) static void CloseInactivePopups() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.OpenPopupStack.empty()) return; @@ -3285,7 +3285,7 @@ static void CloseInactivePopups() static ImGuiWindow* GetFrontMostModalRootWindow() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) if (ImGuiWindow* front_most_popup = g.OpenPopupStack.Data[n].Window) if (front_most_popup->Flags & ImGuiWindowFlags_Modal) @@ -3295,7 +3295,7 @@ static ImGuiWindow* GetFrontMostModalRootWindow() static void ClosePopupToLevel(int remaining) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (remaining > 0) ImGui::FocusWindow(g.OpenPopupStack[remaining-1].Window); else @@ -3307,14 +3307,14 @@ static void ClosePopup(ImGuiID id) { if (!IsPopupOpen(id)) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ClosePopupToLevel(g.OpenPopupStack.Size - 1); } // Close the popup we have begin-ed into. void ImGui::CloseCurrentPopup() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; int popup_idx = g.CurrentPopupStack.Size - 1; if (popup_idx < 0 || popup_idx > g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupID != g.OpenPopupStack[popup_idx].PopupID) return; @@ -3325,14 +3325,14 @@ void ImGui::CloseCurrentPopup() static inline void ClearSetNextWindowData() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowContentSizeCond = g.SetNextWindowCollapsedCond = 0; g.SetNextWindowFocus = false; } static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = window->GetID(str_id); if (!IsPopupOpen(id)) @@ -3371,7 +3371,7 @@ bool ImGui::BeginPopup(const char* str_id) bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = window->GetID(name); if (!IsPopupOpen(id)) @@ -3507,7 +3507,7 @@ void ImGui::EndChild() // Helper to create a child window / scrolling region that looks like a normal widget frame. bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, style.Colors[ImGuiCol_FrameBg]); ImGui::PushStyleVar(ImGuiStyleVar_ChildWindowRounding, style.FrameRounding); @@ -3526,7 +3526,7 @@ void ImGui::EndChildFrame() static void CheckStacksSize(ImGuiWindow* window, bool write) { // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; int* p_backup = &window->DC.StackSizesBackup[0]; { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopID() { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot EndGroup() @@ -3568,7 +3568,7 @@ static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, ImGuiWindow* ImGui::FindWindowByName(const char* name) { // FIXME-OPT: Store sorted hashes -> pointers so we can do a bissection in a contiguous block - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiID id = ImHash(name, 0); for (int i = 0; i < g.Windows.Size; i++) if (g.Windows[i]->ID == id) @@ -3578,7 +3578,7 @@ ImGuiWindow* ImGui::FindWindowByName(const char* name) static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; // Create window the first time ImGuiWindow* window = (ImGuiWindow*)ImGui::MemAlloc(sizeof(ImGuiWindow)); @@ -3658,7 +3658,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; IM_ASSERT(name != NULL); // Window name required IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame() @@ -4208,7 +4208,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us void ImGui::End() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGui::Columns(1, "#CloseColumns"); @@ -4234,7 +4234,7 @@ void ImGui::End() // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. static void Scrollbar(ImGuiWindow* window, bool horizontal) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY"); @@ -4332,7 +4332,7 @@ static void Scrollbar(ImGuiWindow* window, bool horizontal) // Moving window to front of display (which happens to be back of our sorted list) void ImGui::FocusWindow(ImGuiWindow* window) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; // Always mark the window we passed as focused. This is used for keyboard interactions such as tabbing. g.FocusedWindow = window; @@ -4406,7 +4406,7 @@ float ImGui::CalcItemWidth() static void SetCurrentFont(ImFont* font) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; @@ -4417,7 +4417,7 @@ static void SetCurrentFont(ImFont* font) void ImGui::PushFont(ImFont* font) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (!font) font = g.IO.Fonts->Fonts[0]; SetCurrentFont(font); @@ -4427,7 +4427,7 @@ void ImGui::PushFont(ImFont* font) void ImGui::PopFont() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.CurrentWindow->DrawList->PopTextureID(); g.FontStack.pop_back(); SetCurrentFont(g.FontStack.empty() ? g.IO.Fonts->Fonts[0] : g.FontStack.back()); @@ -4477,7 +4477,7 @@ void ImGui::PopTextWrapPos() void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiColMod backup; backup.Col = idx; backup.PreviousValue = g.Style.Colors[idx]; @@ -4487,7 +4487,7 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) void ImGui::PopStyleColor(int count) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; while (count > 0) { ImGuiColMod& backup = g.ColorModifiers.back(); @@ -4499,7 +4499,7 @@ void ImGui::PopStyleColor(int count) static float* GetStyleVarFloatAddr(ImGuiStyleVar idx) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; switch (idx) { case ImGuiStyleVar_Alpha: return &g.Style.Alpha; @@ -4514,7 +4514,7 @@ static float* GetStyleVarFloatAddr(ImGuiStyleVar idx) static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; switch (idx) { case ImGuiStyleVar_WindowPadding: return &g.Style.WindowPadding; @@ -4528,7 +4528,7 @@ static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx) void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; float* pvar = GetStyleVarFloatAddr(idx); IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float. ImGuiStyleMod backup; @@ -4541,7 +4541,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImVec2* pvar = GetStyleVarVec2Addr(idx); IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2. ImGuiStyleMod backup; @@ -4553,7 +4553,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) void ImGui::PopStyleVar(int count) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; while (count > 0) { ImGuiStyleMod& backup = g.StyleModifiers.back(); @@ -4621,31 +4621,31 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) bool ImGui::IsWindowHovered() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.HoveredWindow == g.CurrentWindow && IsWindowContentHoverable(g.HoveredRootWindow); } bool ImGui::IsWindowFocused() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.FocusedWindow == g.CurrentWindow; } bool ImGui::IsRootWindowFocused() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.FocusedWindow == g.CurrentWindow->RootWindow; } bool ImGui::IsRootWindowOrAnyChildFocused() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.FocusedWindow && g.FocusedWindow->RootWindow == g.CurrentWindow->RootWindow; } bool ImGui::IsRootWindowOrAnyChildHovered() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.HoveredRootWindow && (g.HoveredRootWindow == g.CurrentWindow->RootWindow) && IsWindowContentHoverable(g.HoveredRootWindow); } @@ -4663,7 +4663,7 @@ float ImGui::GetWindowHeight() ImVec2 ImGui::GetWindowPos() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; return window->Pos; } @@ -4801,49 +4801,49 @@ void ImGui::SetWindowFocus(const char* name) void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowPosVal = pos; g.SetNextWindowPosCond = cond ? cond : ImGuiSetCond_Always; } void ImGui::SetNextWindowPosCenter(ImGuiSetCond cond) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowPosVal = ImVec2(-FLT_MAX, -FLT_MAX); g.SetNextWindowPosCond = cond ? cond : ImGuiSetCond_Always; } void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowSizeVal = size; g.SetNextWindowSizeCond = cond ? cond : ImGuiSetCond_Always; } void ImGui::SetNextWindowContentSize(const ImVec2& size) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowContentSizeVal = size; g.SetNextWindowContentSizeCond = ImGuiSetCond_Always; } void ImGui::SetNextWindowContentWidth(float width) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowContentSizeVal = ImVec2(width, g.SetNextWindowContentSizeCond ? g.SetNextWindowContentSizeVal.y : 0.0f); g.SetNextWindowContentSizeCond = ImGuiSetCond_Always; } void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowCollapsedVal = collapsed; g.SetNextWindowCollapsedCond = cond ? cond : ImGuiSetCond_Always; } void ImGui::SetNextWindowFocus() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextWindowFocus = true; } @@ -4892,19 +4892,19 @@ float ImGui::GetWindowContentRegionWidth() float ImGui::GetTextLineHeight() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.FontSize; } float ImGui::GetTextLineHeightWithSpacing() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.FontSize + g.Style.ItemSpacing.y; } float ImGui::GetItemsLineHeightWithSpacing() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; } @@ -4931,7 +4931,7 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() void ImGui::SetWindowFontScale(float scale) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->FontWindowScale = scale; g.FontSize = window->CalcFontSize(); @@ -5076,7 +5076,7 @@ void ImGui::TextV(const char* fmt, va_list args) if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); TextUnformatted(g.TempBuffer, text_end); } @@ -5140,7 +5140,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; IM_ASSERT(text != NULL); const char* text_begin = text; if (text_end == NULL) @@ -5250,7 +5250,7 @@ void ImGui::AlignFirstTextHeightToWidgets() return; // Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height. - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ItemSize(ImVec2(0, g.FontSize + g.Style.FramePadding.y*2), g.Style.FramePadding.y); ImGui::SameLine(0, 0); } @@ -5262,7 +5262,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const float w = CalcItemWidth(); @@ -5292,7 +5292,7 @@ void ImGui::LabelText(const char* label, const char* fmt, ...) static inline bool IsWindowContentHoverable(ImGuiWindow* window) { // An active popup disable hovering on other windows (apart from its own children) - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (ImGuiWindow* focused_window = g.FocusedWindow) if (ImGuiWindow* focused_root_window = focused_window->RootWindow) if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow) @@ -5303,7 +5303,7 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window) bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (flags & ImGuiButtonFlags_Disabled) @@ -5376,7 +5376,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -5415,7 +5415,7 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg) // Small buttons fits within text without additional vertical spacing. bool ImGui::SmallButton(const char* label) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; float backup_padding_y = g.Style.FramePadding.y; g.Style.FramePadding.y = 0.0f; bool pressed = ButtonEx(label, ImVec2(0,0), ImGuiButtonFlags_AlignTextBaseLine); @@ -5503,7 +5503,7 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; // Default to using texture ID as ID. User can still push string/integer prefixes. @@ -5535,7 +5535,7 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I // Start logging ImGui output to TTY void ImGui::LogToTTY(int max_depth) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.LogEnabled) return; ImGuiWindow* window = GetCurrentWindowRead(); @@ -5550,7 +5550,7 @@ void ImGui::LogToTTY(int max_depth) // Start logging ImGui output to given file void ImGui::LogToFile(int max_depth, const char* filename) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.LogEnabled) return; ImGuiWindow* window = GetCurrentWindowRead(); @@ -5577,7 +5577,7 @@ void ImGui::LogToFile(int max_depth, const char* filename) // Start logging ImGui output to clipboard void ImGui::LogToClipboard(int max_depth) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.LogEnabled) return; ImGuiWindow* window = GetCurrentWindowRead(); @@ -5591,7 +5591,7 @@ void ImGui::LogToClipboard(int max_depth) void ImGui::LogFinish() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (!g.LogEnabled) return; @@ -5616,7 +5616,7 @@ void ImGui::LogFinish() // Helper to display logging buttons void ImGui::LogButtons() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGui::PushID("LogButtons"); const bool log_to_tty = ImGui::Button("Log To TTY"); @@ -5648,7 +5648,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) return true; // We only write to the tree storage if the user clicks (or explicitely use SetNextTreeNode*** functions) - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiStorage* storage = window->DC.StateStorage; @@ -5695,7 +5695,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; const ImVec2 padding = display_frame ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f); @@ -5820,7 +5820,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags if (p_open) { // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; float button_sz = g.FontSize * 0.5f; if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(window->DC.LastItemRect.Max.x - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz)) *p_open = false; @@ -5844,7 +5844,7 @@ bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); } @@ -5855,7 +5855,7 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); } @@ -5917,7 +5917,7 @@ bool ImGui::TreeNode(const char* label) float ImGui::GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; float off_from_start; if (flags & ImGuiTreeNodeFlags_Framed) off_from_start = g.FontSize + (g.Style.FramePadding.x * 3.0f) - ((float)(int)(g.CurrentWindow->WindowPadding.x*0.5f) - 1); @@ -5928,7 +5928,7 @@ float ImGui::GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags) void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; g.SetNextTreeNodeOpenVal = is_open; g.SetNextTreeNodeOpenCond = cond ? cond : ImGuiSetCond_Always; } @@ -5985,7 +5985,7 @@ void ImGui::Bullet() if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); @@ -6008,7 +6008,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const char* text_begin = g.TempBuffer; @@ -6144,7 +6144,7 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b // Create text input in place of a slider (when CTRL+Clicking on slider) bool ImGui::InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen) @@ -6212,7 +6212,7 @@ float ImGui::RoundScalar(float value, int decimal_precision) bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); const ImGuiStyle& style = g.Style; @@ -6349,7 +6349,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w = CalcItemWidth(); @@ -6412,7 +6412,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); @@ -6487,7 +6487,7 @@ bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_mi if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; bool value_changed = false; ImGui::BeginGroup(); ImGui::PushID(label); @@ -6529,7 +6529,7 @@ bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; bool value_changed = false; ImGui::BeginGroup(); ImGui::PushID(label); @@ -6567,7 +6567,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; // Draw frame @@ -6646,7 +6646,7 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w = CalcItemWidth(); @@ -6709,7 +6709,7 @@ bool ImGui::DragFloatN(const char* label, float* v, int components, float v_spee if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; bool value_changed = false; ImGui::BeginGroup(); ImGui::PushID(label); @@ -6751,7 +6751,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGui::PushID(label); ImGui::BeginGroup(); PushMultiItemsWidths(2); @@ -6787,7 +6787,7 @@ bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, i if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; bool value_changed = false; ImGui::BeginGroup(); ImGui::PushID(label); @@ -6829,7 +6829,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGui::PushID(label); ImGui::BeginGroup(); PushMultiItemsWidths(2); @@ -6854,7 +6854,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -6996,7 +6996,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; ImVec2 pos = window->DC.CursorPos; @@ -7031,7 +7031,7 @@ bool ImGui::Checkbox(const char* label, bool* v) if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -7094,7 +7094,7 @@ bool ImGui::RadioButton(const char* label, bool active) if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -7418,7 +7418,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; @@ -7992,7 +7992,7 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -8065,7 +8065,7 @@ bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; bool value_changed = false; ImGui::BeginGroup(); ImGui::PushID(label); @@ -8108,7 +8108,7 @@ bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextF if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; bool value_changed = false; ImGui::BeginGroup(); ImGui::PushID(label); @@ -8201,7 +8201,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w = CalcItemWidth(); @@ -8310,7 +8310,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1) @@ -8491,7 +8491,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImVec2 pos = window->DC.CursorPos; ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); @@ -8525,7 +8525,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool ImGui::BeginMainMenuBar() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); ImGui::SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.FontBaseSize + g.Style.FramePadding.y * 2.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); @@ -8591,7 +8591,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); @@ -8701,7 +8701,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID("#colorbutton"); const float square_size = g.FontSize; @@ -8742,7 +8742,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) if (window->SkipItems) return false; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); const float w_full = CalcItemWidth(); @@ -8903,7 +8903,7 @@ void ImGui::Separator() window->DrawList->AddLine(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border)); - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.LogEnabled) ImGui::LogText(IM_NEWLINE "--------------------------------"); @@ -9003,7 +9003,7 @@ void ImGui::SameLine(float pos_x, float spacing_w) if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (pos_x != 0.0f) { if (spacing_w < 0.0f) spacing_w = 0.0f; @@ -9026,7 +9026,7 @@ void ImGui::NextColumn() if (window->SkipItems) return; - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (window->DC.ColumnsCount > 1) { ImGui::PopItemWidth(); @@ -9072,7 +9072,7 @@ static float GetDraggedColumnOffset(int column_index) { // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindowRead(); IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets. IM_ASSERT(g.ActiveId == window->DC.ColumnsSetID + ImGuiID(column_index)); @@ -9085,7 +9085,7 @@ static float GetDraggedColumnOffset(int column_index) float ImGui::GetColumnOffset(int column_index) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindowRead(); if (column_index < 0) column_index = window->DC.ColumnsCurrent; @@ -9140,7 +9140,7 @@ static void PushColumnClipRect(int column_index) void ImGui::Columns(int columns_count, const char* id, bool border) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); IM_ASSERT(columns_count >= 1); @@ -9232,7 +9232,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) void ImGui::Indent() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->DC.IndentX += g.Style.IndentSpacing; window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX; @@ -9240,7 +9240,7 @@ void ImGui::Indent() void ImGui::Unindent() { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->DC.IndentX -= g.Style.IndentSpacing; window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX; @@ -9397,7 +9397,7 @@ static const char* GetClipboardTextFn_DefaultImpl() // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers static void SetClipboardTextFn_DefaultImpl(const char* text) { - ImGuiState& g = *GImGui; + ImGuiContext& g = *GImGui; if (g.PrivateClipboard) { ImGui::MemFree(g.PrivateClipboard); @@ -9534,7 +9534,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) } }; - ImGuiState& g = *GImGui; // Access private state + ImGuiContext& g = *GImGui; // Access private state Funcs::NodeWindows(g.Windows, "Windows"); if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.RenderDrawLists[0].Size)) { diff --git a/imgui.h b/imgui.h index d5479803..ad97c2a1 100644 --- a/imgui.h +++ b/imgui.h @@ -54,7 +54,7 @@ struct ImGuiTextFilter; // Parse and apply text filters. In format " struct ImGuiTextBuffer; // Text buffer for logging/accumulating text struct ImGuiTextEditCallbackData; // Shared state of ImGui::InputText() when using custom callbacks (advanced) struct ImGuiListClipper; // Helper to manually clip large list of items -struct ImGuiState; // ImGui context (opaque) +struct ImGuiContext; // ImGui context (opaque) // Enumerations (declared as int for compatibility and to not pollute the top of this file) typedef unsigned int ImU32; @@ -445,10 +445,10 @@ namespace ImGui // Internal context access - if you want to use multiple context, share context between modules (e.g. DLL). There is a default context created and active by default. IMGUI_API const char* GetVersion(); - IMGUI_API ImGuiState* CreateContext(void* (*malloc_fn)(size_t) = NULL, void (*free_fn)(void*) = NULL); - IMGUI_API void DestroyContext(ImGuiState* ctx); - IMGUI_API ImGuiState* GetCurrentContext(); - IMGUI_API void SetCurrentContext(ImGuiState* ctx); + IMGUI_API ImGuiContext* CreateContext(void* (*malloc_fn)(size_t) = NULL, void (*free_fn)(void*) = NULL); + IMGUI_API void DestroyContext(ImGuiContext* ctx); + IMGUI_API ImGuiContext* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiContext* ctx); // Obsolete (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_internal.h b/imgui_internal.h index 4eee4f7d..bf4f73f1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -70,7 +70,7 @@ namespace ImGuiStb // Context //----------------------------------------------------------------------------- -extern IMGUI_API ImGuiState* GImGui; // current implicit ImGui context pointer +extern IMGUI_API ImGuiContext* GImGui; // current implicit ImGui context pointer //----------------------------------------------------------------------------- // Helpers @@ -344,7 +344,7 @@ struct ImGuiPopupRef }; // Main state for ImGui -struct ImGuiState +struct ImGuiContext { bool Initialized; ImGuiIO IO; @@ -436,7 +436,7 @@ struct ImGuiState int CaptureKeyboardNextFrame; char TempBuffer[1024*3+1]; // temporary text buffer - ImGuiState() + ImGuiContext() { Initialized = false; Font = NULL; @@ -672,8 +672,8 @@ namespace ImGui // 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. - inline ImGuiWindow* GetCurrentWindowRead() { ImGuiState& g = *GImGui; return g.CurrentWindow; } - inline ImGuiWindow* GetCurrentWindow() { ImGuiState& g = *GImGui; g.CurrentWindow->Accessed = true; return g.CurrentWindow; } + inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } + inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->Accessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* GetParentWindow(); IMGUI_API ImGuiWindow* FindWindowByName(const char* name); IMGUI_API void FocusWindow(ImGuiWindow* window); From 834bfe4af5eb8ff7e0d04014ca156b67efa64aaf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 20:11:14 +0200 Subject: [PATCH 154/400] Examples: DirectX11: Fixed handle leak + minor coding style fix for #640 --- .../directx11_example/imgui_impl_dx11.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 33afb7ea..c43c6cf1 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -34,8 +34,8 @@ static ID3D11SamplerState* g_pFontSampler = NULL; static ID3D11ShaderResourceView*g_pFontTextureView = NULL; static ID3D11RasterizerState* g_pRasterizerState = NULL; static ID3D11BlendState* g_pBlendState = NULL; +static ID3D11DepthStencilState* g_pDepthStencilState = NULL; static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000; -static ID3D11DepthStencilState* g_pDSState = NULL; struct VERTEX_CONSTANT_BUFFER { @@ -128,6 +128,8 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ID3D11BlendState* BlendState; FLOAT BlendFactor[4]; UINT SampleMask; + UINT StencilRef; + ID3D11DepthStencilState* DepthStencilState; ID3D11ShaderResourceView* PSShaderResource; ID3D11SamplerState* PSSampler; ID3D11PixelShader* PS; @@ -139,8 +141,6 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; DXGI_FORMAT IndexBufferFormat; ID3D11InputLayout* InputLayout; - ID3D11DepthStencilState* DepthStencilState; - UINT StencilRef; }; BACKUP_DX11_STATE old; old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; @@ -148,6 +148,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); ctx->RSGetState(&old.RS); ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); ctx->PSGetSamplers(0, 1, &old.PSSampler); old.PSInstancesCount = old.VSInstancesCount = 256; @@ -158,7 +159,6 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); ctx->IAGetInputLayout(&old.InputLayout); - ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); // Setup viewport D3D11_VIEWPORT vp; @@ -185,8 +185,8 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) // Setup render state const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->OMSetDepthStencilState(g_pDepthStencilState, 0); ctx->RSSetState(g_pRasterizerState); - ctx->OMSetDepthStencilState( g_pDSState, 1 ); // Render command lists int vtx_offset = 0; @@ -218,6 +218,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->RSSetViewports(old.ViewportsCount, old.Viewports); ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); @@ -229,7 +230,6 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); - ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); } IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) @@ -454,16 +454,15 @@ bool ImGui_ImplDX11_CreateDeviceObjects() g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState); } - // Create Depth-Stencil State { D3D11_DEPTH_STENCIL_DESC desc; ZeroMemory(&desc, sizeof(desc)); - desc.StencilEnable = false; desc.DepthEnable = true; desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; desc.DepthFunc = D3D11_COMPARISON_ALWAYS; - g_pd3dDevice->CreateDepthStencilState( &desc, &g_pDSState ); + desc.StencilEnable = false; + g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState); } ImGui_ImplDX11_CreateFontsTexture(); @@ -482,6 +481,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; } + if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; } if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; } if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; } if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; } @@ -489,7 +489,6 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; } if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; } if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; } - if (g_pDSState) { g_pDSState->Release(); g_pDSState = NULL; } } bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContext* device_context) From f4633d09acbbcdbc948b55b82edf93595b27db9f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 20:19:04 +0200 Subject: [PATCH 155/400] Examples: DirectX10, DirectX11: Removed seemingly unnecessary bunch of rasterizer state creation code. --- examples/directx10_example/main.cpp | 21 --------------------- examples/directx11_example/main.cpp | 21 --------------------- 2 files changed, 42 deletions(-) diff --git a/examples/directx10_example/main.cpp b/examples/directx10_example/main.cpp index f47f9d5d..a418da9f 100644 --- a/examples/directx10_example/main.cpp +++ b/examples/directx10_example/main.cpp @@ -63,27 +63,6 @@ HRESULT CreateDeviceD3D(HWND hWnd) if (D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice) != S_OK) return E_FAIL; - // Setup rasterizer - { - D3D10_RASTERIZER_DESC RSDesc; - memset(&RSDesc, 0, sizeof(D3D10_RASTERIZER_DESC)); - RSDesc.FillMode = D3D10_FILL_SOLID; - RSDesc.CullMode = D3D10_CULL_NONE; - RSDesc.FrontCounterClockwise = FALSE; - RSDesc.DepthBias = 0; - RSDesc.SlopeScaledDepthBias = 0.0f; - RSDesc.DepthBiasClamp = 0; - RSDesc.DepthClipEnable = TRUE; - RSDesc.ScissorEnable = TRUE; - RSDesc.AntialiasedLineEnable = FALSE; - RSDesc.MultisampleEnable = (sd.SampleDesc.Count > 1) ? TRUE : FALSE; - - ID3D10RasterizerState* pRState = NULL; - g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState); - g_pd3dDevice->RSSetState(pRState); - pRState->Release(); - } - CreateRenderTarget(); return S_OK; diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index d90f49c8..a47e22d0 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -65,27 +65,6 @@ HRESULT CreateDeviceD3D(HWND hWnd) if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK) return E_FAIL; - // Setup rasterizer - { - D3D11_RASTERIZER_DESC RSDesc; - memset(&RSDesc, 0, sizeof(D3D11_RASTERIZER_DESC)); - RSDesc.FillMode = D3D11_FILL_SOLID; - RSDesc.CullMode = D3D11_CULL_NONE; - RSDesc.FrontCounterClockwise = FALSE; - RSDesc.DepthBias = 0; - RSDesc.SlopeScaledDepthBias = 0.0f; - RSDesc.DepthBiasClamp = 0; - RSDesc.DepthClipEnable = TRUE; - RSDesc.ScissorEnable = TRUE; - RSDesc.AntialiasedLineEnable = FALSE; - RSDesc.MultisampleEnable = (sd.SampleDesc.Count > 1) ? TRUE : FALSE; - - ID3D11RasterizerState* pRState = NULL; - g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState); - g_pd3dDeviceContext->RSSetState(pRState); - pRState->Release(); - } - CreateRenderTarget(); return S_OK; From 656b1e848cc77a7a0f057113d8bccc49d5c04cda Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 20:53:55 +0200 Subject: [PATCH 156/400] Examples: DirectX11: Fixed uninitialized fields. Disabling depth-write (#640, #636) --- examples/directx11_example/imgui_impl_dx11.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index c43c6cf1..d595e6c0 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -454,14 +454,17 @@ bool ImGui_ImplDX11_CreateDeviceObjects() g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState); } - // Create Depth-Stencil State + // Create depth-stencil State { D3D11_DEPTH_STENCIL_DESC desc; ZeroMemory(&desc, sizeof(desc)); - desc.DepthEnable = true; + desc.DepthEnable = false; desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; desc.DepthFunc = D3D11_COMPARISON_ALWAYS; desc.StencilEnable = false; + desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.BackFace = desc.FrontFace; g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState); } From 2ef766a1cec4e3cf71e0920a6ca0efd0edbbe4bc Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 20:57:38 +0200 Subject: [PATCH 157/400] Examples: DirectX10: Apply depth-stencil state like DirectX11 example (#640, #636) --- .../directx10_example/imgui_impl_dx10.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index f0e57f72..15dbed20 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -34,6 +34,7 @@ static ID3D10SamplerState* g_pFontSampler = NULL; static ID3D10ShaderResourceView*g_pFontTextureView = NULL; static ID3D10RasterizerState* g_pRasterizerState = NULL; static ID3D10BlendState* g_pBlendState = NULL; +static ID3D10DepthStencilState* g_pDepthStencilState = NULL; static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000; struct VERTEX_CONSTANT_BUFFER @@ -125,6 +126,8 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) ID3D10BlendState* BlendState; FLOAT BlendFactor[4]; UINT SampleMask; + UINT StencilRef; + ID3D10DepthStencilState* DepthStencilState; ID3D10ShaderResourceView* PSShaderResource; ID3D10SamplerState* PSSampler; ID3D10PixelShader* PS; @@ -141,6 +144,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); ctx->RSGetState(&old.RS); ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); ctx->PSGetSamplers(0, 1, &old.PSSampler); ctx->PSGetShader(&old.PS); @@ -176,6 +180,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) // Setup render state const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->OMSetDepthStencilState(g_pDepthStencilState, 0); ctx->RSSetState(g_pRasterizerState); // Render command lists @@ -208,6 +213,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) ctx->RSSetViewports(old.ViewportsCount, old.Viewports); ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release(); @@ -447,6 +453,20 @@ bool ImGui_ImplDX10_CreateDeviceObjects() g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState); } + // Create depth-stencil State + { + D3D10_DEPTH_STENCIL_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.DepthEnable = false; + desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL; + desc.DepthFunc = D3D10_COMPARISON_ALWAYS; + desc.StencilEnable = false; + desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; + desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS; + desc.BackFace = desc.FrontFace; + g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState); + } + ImGui_ImplDX10_CreateFontsTexture(); return true; @@ -463,6 +483,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; } + if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; } if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; } if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; } if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; } From 36ca8a8194e86999fb83547b8ec302cb2d4b1b4b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 7 May 2016 21:09:53 +0200 Subject: [PATCH 158/400] Minor warnings fixes. --- imgui.cpp | 2 +- stb_rect_pack.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3dfa7cff..80d84737 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6274,7 +6274,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v { // Positive: rescale to the positive range before powering float a; - if (fabsf(linear_zero_pos - 1.0f) > 1.e-6) + if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f) a = (normalized_pos - linear_zero_pos) / (1.0f - linear_zero_pos); else a = normalized_pos; diff --git a/stb_rect_pack.h b/stb_rect_pack.h index d7e899c4..fafd8897 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -268,9 +268,9 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, } // find minimum y position if it starts at x1 -static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) +static int stbrp__skyline_find_min_y(stbrp_context *, stbrp_node *first, int x0, int width, int *pwaste) { - (void)c; + //(void)c; stbrp_node *node = first; int x1 = x0 + width; int min_y, visited_width, waste_area; From 8a0d3b9628d4b92a2d7d2a4a7b9424a745c76d9d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 May 2016 11:49:21 +0200 Subject: [PATCH 159/400] Examples; DirectX10/11: Added comments about removing dependency on d3dcompiler DLL (#638) --- examples/directx10_example/imgui_impl_dx10.cpp | 6 ++++++ examples/directx10_example/main.cpp | 1 - examples/directx11_example/imgui_impl_dx11.cpp | 6 ++++++ examples/directx11_example/main.cpp | 1 - 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 15dbed20..bccee87e 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -343,6 +343,12 @@ bool ImGui_ImplDX10_CreateDeviceObjects() if (g_pFontSampler) ImGui_ImplDX10_InvalidateDeviceObjects(); + // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) + // If you would like to use this DX11 sample code but remove this dependency you can: + // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [prefered solution] + // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. + // See https://github.com/ocornut/imgui/pull/638 for sources and details. + // Create the vertex shader { static const char* vertexShader = diff --git a/examples/directx10_example/main.cpp b/examples/directx10_example/main.cpp index a418da9f..fb98cad1 100644 --- a/examples/directx10_example/main.cpp +++ b/examples/directx10_example/main.cpp @@ -5,7 +5,6 @@ #include "imgui_impl_dx10.h" #include #include -#include #define DIRECTINPUT_VERSION 0x0800 #include #include diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index d595e6c0..11f66f0e 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -345,6 +345,12 @@ bool ImGui_ImplDX11_CreateDeviceObjects() if (g_pFontSampler) ImGui_ImplDX11_InvalidateDeviceObjects(); + // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) + // If you would like to use this DX11 sample code but remove this dependency you can: + // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [prefered solution] + // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. + // See https://github.com/ocornut/imgui/pull/638 for sources and details. + // Create the vertex shader { static const char* vertexShader = diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index a47e22d0..e3fe5aa7 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -4,7 +4,6 @@ #include #include "imgui_impl_dx11.h" #include -#include #define DIRECTINPUT_VERSION 0x0800 #include #include From aa11934efafe4db75993e23aacacf9ed8b1dd40c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 8 May 2016 17:12:54 +0200 Subject: [PATCH 160/400] Comments to clarify default shared ImFontAtlas and current context pointer thread-safety (#586, #591) --- imgui.cpp | 12 ++++++------ imgui.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f031f990..171b64b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -696,15 +696,15 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); // Context //----------------------------------------------------------------------------- -// We access everything through this pointer (always assumed to be != NULL) -// You can swap the pointer to a different context by calling ImGui::SetCurrentContext() +// Default context, default font atlas. +// New contexts always point by default to this font atlas. It can be changed by reassigning the GetIO().Fonts variable. static ImGuiContext GImDefaultContext; -ImGuiContext* GImGui = &GImDefaultContext; - -// Statically allocated default font atlas. This is merely a maneuver to keep ImFontAtlas definition at the bottom of the .h file (otherwise it'd be inside ImGuiIO) -// Also we wouldn't be able to new() one at this point, before users have a chance to setup their allocator. static ImFontAtlas GImDefaultFontAtlas; +// Current context pointer. Implicitely used by all ImGui functions. Always assumed to be != NULL. Change to a different context by calling ImGui::SetCurrentContext() +// ImGui is currently not thread-safe because of this variable. If you want thread-safety to allow N threads to access N different contexts, you might work around it by (A) having two instances of the ImGui code under different namespaces or (B) change this variable to be TLS. Further development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +ImGuiContext* GImGui = &GImDefaultContext; + //----------------------------------------------------------------------------- // User facing structures //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index ad97c2a1..2ba21a40 100644 --- a/imgui.h +++ b/imgui.h @@ -444,6 +444,7 @@ namespace ImGui IMGUI_API void SetClipboardText(const char* text); // Internal context access - if you want to use multiple context, share context between modules (e.g. DLL). There is a default context created and active by default. + // 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. IMGUI_API const char* GetVersion(); IMGUI_API ImGuiContext* CreateContext(void* (*malloc_fn)(size_t) = NULL, void (*free_fn)(void*) = NULL); IMGUI_API void DestroyContext(ImGuiContext* ctx); From 4b5a4cae09d0efd32c64b510490672d35bbccb51 Mon Sep 17 00:00:00 2001 From: cosmy1 Date: Mon, 9 May 2016 00:21:05 +0200 Subject: [PATCH 161/400] Fix compilation errors when disabling test windows. --- imgui_demo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c19e2b5b..cdeb2cef 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2459,7 +2459,7 @@ static void ShowExampleAppLongText(bool* p_open) #else void ImGui::ShowTestWindow(bool*) {} -void ImGui::ShowUserGuide(bool*) {} -void ImGui::ShowStyleEditor(bool*) {} +void ImGui::ShowUserGuide() {} +void ImGui::ShowStyleEditor(ImGuiStyle*) {} #endif From a59a04f4d0822b69150433fb7cbf70e944874c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Mon, 9 May 2016 13:27:44 -0700 Subject: [PATCH 162/400] Fixed iOS/OSX build. --- imgui.cpp | 3 +-- imgui_demo.cpp | 3 +-- imgui_draw.cpp | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 171b64b4..d9ea1d2e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -621,8 +621,7 @@ #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' // -#endif -#ifdef __GNUC__ +#elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c19e2b5b..9a6a8522 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -31,8 +31,7 @@ #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // -#endif -#ifdef __GNUC__ +#elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function diff --git a/imgui_draw.cpp b/imgui_draw.cpp index efbda15b..57b13bf8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -38,8 +38,7 @@ #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // -#endif -#ifdef __GNUC__ +#elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value From b630cb5b427081e724d2b452ba7d20bcddf6a686 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 May 2016 17:00:42 +0200 Subject: [PATCH 163/400] ImGuiWindow: Storing ParentWindow (#615, #646) --- imgui.cpp | 2 ++ imgui_internal.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index d9ea1d2e..a849ba5a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1641,6 +1641,7 @@ ImGuiWindow::ImGuiWindow(const char* name) DrawList->_OwnerName = Name; RootWindow = NULL; RootNonPopupWindow = NULL; + ParentWindow = NULL; FocusIdxAllCounter = FocusIdxTabCounter = -1; FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = IM_INT_MAX; @@ -3759,6 +3760,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us for (root_non_popup_idx = root_idx; root_non_popup_idx > 0; root_non_popup_idx--) if (!(g.CurrentWindowStack[root_non_popup_idx]->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) break; + window->ParentWindow = parent_window; window->RootWindow = g.CurrentWindowStack[root_idx]; window->RootNonPopupWindow = g.CurrentWindowStack[root_non_popup_idx]; // This is merely for displaying the TitleBgActive color. diff --git a/imgui_internal.h b/imgui_internal.h index bf4f73f1..6c90e53a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -636,7 +636,8 @@ struct IMGUI_API ImGuiWindow float FontWindowScale; // Scale multiplier per-window ImDrawList* DrawList; ImGuiWindow* RootWindow; // If we are a child window, this is pointing to the first non-child parent window. Else point to ourself. - ImGuiWindow* RootNonPopupWindow; // If we are a child widnow, this is pointing to the first non-child non-popup parent window. Else point to ourself. + ImGuiWindow* RootNonPopupWindow; // If we are a child window, this is pointing to the first non-child non-popup parent window. Else point to ourself. + ImGuiWindow* ParentWindow; // If we are a child window, this is pointing to our parent window. Else point to NULL. // Focus int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() From 8648346eab5a485c5006a6a9473fe6c9d3eb4fe6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 May 2016 17:02:10 +0200 Subject: [PATCH 164/400] Modal: fixed non-child window stacked over a modal losing its hoverabilty/focusability (#615, #604) --- imgui.cpp | 5 ++++- imgui_demo.cpp | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a849ba5a..b77a00aa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2085,7 +2085,10 @@ void ImGui::NewFrame() if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow()) { g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f); - if (g.HoveredRootWindow != modal_window) + ImGuiWindow* window = g.HoveredRootWindow; + while (window && window != modal_window) + window = window->ParentWindow; + if (!window) g.HoveredRootWindow = g.HoveredWindow = NULL; } else diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9a6a8522..3a2296e6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1244,6 +1244,9 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); ImGui::Separator(); + //static int dummy_i = 0; + //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0"); + static bool dont_ask_me_next_time = false; ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0)); ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); From 91f11fb1bd4d53ec5933c319650ac2ccb5da286a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 May 2016 09:58:43 +0200 Subject: [PATCH 165/400] Comments / todos --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index b77a00aa..b3d87cce 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -556,6 +556,9 @@ - style: WindowPadding needs to be EVEN needs the 0.5 multiplier probably have a subtle effect on clip rectangle - text: simple markup language for color change? - font: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier. + - font: small opt: for monospace font (like the defalt one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance + - font: add support for kerning, probably optional. perhaps default to (32..128)^2 matrix ~ 36KB then hash fallback. + - font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize) - font: fix AddRemapChar() to work before font has been built. - log: LogButtons() options for specifying depth and/or hiding depth slider - log: have more control over the log scope (e.g. stop logging when leaving current tree node scope) From ed20fcf9d5399d1e59bc40c2fd59d71f5ee9c95a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 May 2016 10:31:30 +0200 Subject: [PATCH 166/400] Fixed incorrect parameter to ButtonBehavior() in Columns code - had no side-effect (#649) Broken in 3eabad0321b7b7e949a87b3c6339fc5bea3403e7 --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index b3d87cce..78622fff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9179,7 +9179,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) continue; bool hovered, held; - ButtonBehavior(column_rect, column_id, &hovered, &held, true); + ButtonBehavior(column_rect, column_id, &hovered, &held); if (hovered || held) g.MouseCursor = ImGuiMouseCursor_ResizeEW; From 2f55dc1f335a3d63591af4b10a8a83545a15ab3b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 May 2016 11:58:05 +0200 Subject: [PATCH 167/400] ImFontConfig: Clarified persistence requirement of GlyphRanges array (#651) --- imgui.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 2ba21a40..0f260ed4 100644 --- a/imgui.h +++ b/imgui.h @@ -1254,7 +1254,7 @@ struct ImFontConfig int OversampleH, OversampleV; // 3, 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every character to pixel boundary (if enabled, set OversampleH/V to 1) ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs - const ImWchar* GlyphRanges; // // List of Unicode range (2 value per range, values are inclusive, zero-terminated list) + const ImWchar* GlyphRanges; // // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). bool MergeGlyphCenterV; // false // When merging (multiple ImFontInput for one ImFont), vertically center new glyphs instead of aligning their baseline @@ -1273,6 +1273,7 @@ struct ImFontConfig // 3. Upload the pixels data into a texture within your graphics system. // 4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture. // 5. Call ClearTexData() to free textures memory on the heap. +// NB: If you use a 'glyph_ranges' array you need to make sure that your array persist up until the ImFont is cleared. We only copy the pointer, not the data. struct ImFontAtlas { IMGUI_API ImFontAtlas(); From b628acbb5271f92db3903c4b2f9fff0d2b1b5d7b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 May 2016 20:59:20 +0200 Subject: [PATCH 168/400] StyleEditor: comments (#652) --- imgui.h | 2 +- imgui_demo.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui.h b/imgui.h index 0f260ed4..fecfe3bf 100644 --- a/imgui.h +++ b/imgui.h @@ -110,7 +110,7 @@ namespace ImGui IMGUI_API void Render(); // ends the ImGui frame, finalize rendering data, then call your io.RenderDrawListsFn() function if set. IMGUI_API void Shutdown(); IMGUI_API void ShowUserGuide(); // help block - IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block. you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) IMGUI_API void ShowTestWindow(bool* p_open = NULL); // test window demonstrating ImGui features IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // metrics window for debugging ImGui diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 768c4480..8f48fab3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1554,9 +1554,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { ImGuiStyle& style = ImGui::GetStyle(); - const ImGuiStyle def; // Default style + // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to the default style) + const ImGuiStyle default_style; // Default style if (ImGui::Button("Revert Style")) - style = ref ? *ref : def; + style = ref ? *ref : default_style; + if (ref) { ImGui::SameLine(); @@ -1611,7 +1613,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { const ImVec4& col = style.Colors[i]; const char* name = ImGui::GetStyleColName(i); - if (!output_only_modified || memcmp(&col, (ref ? &ref->Colors[i] : &def.Colors[i]), sizeof(ImVec4)) != 0) + if (!output_only_modified || memcmp(&col, (ref ? &ref->Colors[i] : &default_style.Colors[i]), sizeof(ImVec4)) != 0) ImGui::LogText("style.Colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 22 - (int)strlen(name), "", col.x, col.y, col.z, col.w); } ImGui::LogFinish(); @@ -1640,9 +1642,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) continue; ImGui::PushID(i); ImGui::ColorEdit4(name, (float*)&style.Colors[i], true); - if (memcmp(&style.Colors[i], (ref ? &ref->Colors[i] : &def.Colors[i]), sizeof(ImVec4)) != 0) + if (memcmp(&style.Colors[i], (ref ? &ref->Colors[i] : &default_style.Colors[i]), sizeof(ImVec4)) != 0) { - ImGui::SameLine(); if (ImGui::Button("Revert")) style.Colors[i] = ref ? ref->Colors[i] : def.Colors[i]; + ImGui::SameLine(); if (ImGui::Button("Revert")) style.Colors[i] = ref ? ref->Colors[i] : default_style.Colors[i]; if (ref) { ImGui::SameLine(); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; } } ImGui::PopID(); From 8d5b2fba95907d84fb541bddaec900b2e197297c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 May 2016 23:12:55 +0200 Subject: [PATCH 169/400] Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, being inconsistent and causing visual artefact (#655) Broke the meaning of TitleBg and TitleBgActive. Only affect values where Alpha<1.0f. Fixed default theme. --- imgui.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 78622fff..9137f450 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -153,6 +153,14 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/05/12 (1.49) - title bar (using TitleBg/TitleBgActive colors) isn't rendered over a window background (WindowBg color) anymore. + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given that color and the WindowBg color. + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) + { + float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; + return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); + } - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). @@ -746,9 +754,9 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f); Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); - Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); + Colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); - Colors[ImGuiCol_TitleBgActive] = ImVec4(0.50f, 0.50f, 1.00f, 0.55f); + Colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); @@ -4056,7 +4064,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us bg_color.w = bg_alpha; bg_color.w *= style.Alpha; if (bg_color.w > 0.0f) - window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding); + window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 15 : 4|8); // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) From a2a5d715829ebe37162c613c8649a71f6ff4590f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 May 2016 23:13:54 +0200 Subject: [PATCH 170/400] Demo: Tweak irritating pink color. --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8f48fab3..3961b220 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1218,7 +1218,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::EndPopup(); } - static ImVec4 color = ImColor(1.0f, 0.0f, 1.0f, 1.0f); + static ImVec4 color = ImColor(0.8f, 0.5f, 1.0f, 1.0f); ImGui::ColorButton(color); if (ImGui::BeginPopupContextItem("color context menu")) { From e1e2752dcbfb1160b355d83bbc9301e36dcacd20 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 May 2016 10:50:59 +0200 Subject: [PATCH 171/400] Fixed repeating button behavior triggering twice, typically affect the +/- of InputInt/InputFloat and user repeating buttons (#656) + Took note of further work Broken in 547f34cf22640526b63f02f50c73ef9409e8acab --- imgui.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 9137f450..bee8bb79 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5357,7 +5357,11 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool pressed = true; SetActiveID(0); } - if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && ImGui::IsMouseClicked(0, true)) + + // 'Repeat' mode acts when held regardless of _PressedOn flags + // FIXME: Need to clarify the repeat behavior with those differents flags. Currently the typical PressedOnClickRelease+Repeat will add an extra click on final release (hardly noticeable with repeat rate, but technically an issue) + // Relies on repeat behavior of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && ImGui::IsMouseClicked(0, true)) pressed = true; } } From f48f9a30ef5f598e3fa9ac42e07a89b78c5dbc74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 May 2016 11:13:54 +0200 Subject: [PATCH 172/400] ButtonBehavior(), fixed subtle old bug when a repeating button would also return true on release + comments (#656) --- imgui.cpp | 18 ++++++++++++------ imgui.h | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bee8bb79..a9e64892 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5341,7 +5341,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetHoveredID(id); if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { - if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0]) // Most common type + // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat + // PressedOnClickRelease | * | .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds + // PressedOnClick | | .. + // PressedOnRelease | | .. (NOT on release) + // PressedOnDoubleClick | | .. + if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0]) { SetActiveID(id, window); // Hold on ID FocusWindow(window); @@ -5354,13 +5359,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) { - pressed = true; + if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps + pressed = true; SetActiveID(0); } - // 'Repeat' mode acts when held regardless of _PressedOn flags - // FIXME: Need to clarify the repeat behavior with those differents flags. Currently the typical PressedOnClickRelease+Repeat will add an extra click on final release (hardly noticeable with repeat rate, but technically an issue) - // Relies on repeat behavior of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). + // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && ImGui::IsMouseClicked(0, true)) pressed = true; } @@ -5376,7 +5381,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool else { if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease)) - pressed = true; + if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps + pressed = true; SetActiveID(0); } } diff --git a/imgui.h b/imgui.h index fecfe3bf..38e36762 100644 --- a/imgui.h +++ b/imgui.h @@ -732,7 +732,7 @@ struct ImGuiIO float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array - float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds. (for actions where 'repeat' is active) + float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). float KeyRepeatRate; // = 0.020f // When holding a key/button, rate at which it repeats, in seconds. void* UserData; // = NULL // Store your own data for retrieval by callbacks. From e79d2828c447647cb1ed0554f8df5484259bcb09 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 May 2016 23:10:16 +0200 Subject: [PATCH 173/400] Metrics window: coarse clipping the detailed vertex buffer for pleasure and benefits. --- imgui.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a9e64892..5680cc04 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9507,12 +9507,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); continue; } + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); if (show_clip_rects && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; ImRect vtxs_rect; - ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++) vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos); clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255)); @@ -9520,20 +9520,22 @@ void ImGui::ShowMetricsWindow(bool* p_open) } if (!pcmd_node_open) continue; - for (int i = elem_offset; i+2 < elem_offset + (int)pcmd->ElemCount; i += 3) + ImGuiListClipper clipper(pcmd->ElemCount/3, ImGui::GetTextLineHeight()*3 + ImGui::GetStyle().ItemSpacing.y); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { - ImVec2 triangles_pos[3]; char buf[300], *buf_p = buf; - for (int n = 0; n < 3; n++) + ImVec2 triangles_pos[3]; + for (int n = 0; n < 3; n++, vtx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[(draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data[i+n] : i+n]; + ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; triangles_pos[n] = v.pos; - buf_p += sprintf(buf_p, "vtx %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", i+n, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (ImGui::IsItemHovered()) overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle } + clipper.End(); ImGui::TreePop(); } overlay_draw_list->PopClipRect(); From 39bda5ea09ec94d31590cc7a3d515a30a1f6d9a5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 14 May 2016 10:22:25 +0200 Subject: [PATCH 174/400] Fixed a IMGUI_API->inline case (#657, #349) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 38e36762..64488503 100644 --- a/imgui.h +++ b/imgui.h @@ -791,7 +791,7 @@ struct ImGuiIO // Functions IMGUI_API void AddInputCharacter(ImWchar c); // Helper to add a new character into InputCharacters[] IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Helper to add new characters into InputCharacters[] from an UTF-8 string - IMGUI_API void ClearInputCharacters() { InputCharacters[0] = 0; } // Helper to clear the text input buffer + inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Helper to clear the text input buffer //------------------------------------------------------------------ // Output - Retrieve after calling NewFrame(), you can use them to discard inputs or hide them from the rest of your application From 431eaf1abe15ec21a47b7c44a8e168af75249c2f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 14 May 2016 15:35:50 +0200 Subject: [PATCH 175/400] Comments to clarify what float[2] int[2] etc. are. May switch to pointers? (#659) --- imgui.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 64488503..c201b077 100644 --- a/imgui.h +++ b/imgui.h @@ -261,8 +261,8 @@ namespace ImGui IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items = -1); // separate items with \0, end item-list with \0\0 IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); IMGUI_API bool ColorButton(const ImVec4& col, bool small_height = false, bool outline_border = true); - IMGUI_API bool ColorEdit3(const char* label, float col[3]); - IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true); + IMGUI_API bool ColorEdit3(const char* label, float col[3]); // Hint: 'float col[3]' function argument is same as 'float* col'. You can pass address of first element out of a contiguous set, e.g. &myvector.x + IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true); // " IMGUI_API void ColorEditMode(ImGuiColorEditMode mode); // FIXME-OBSOLETE: This is inconsistent with most of the API and should be obsoleted. IMGUI_API 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), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); @@ -271,6 +271,7 @@ namespace ImGui IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1,0), const char* overlay = NULL); // Widgets: Drags (tip: ctrl+click on a drag box to input with keyboard. manually input values aren't clamped, can go off-bounds) + // For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, remember than a 'float v[3]' function argument is the same as 'float* v'. You can pass address of your first element out of a contiguous set, e.g. &myvector.x IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f); From 9e6ed0991df75964f96ba64fbd79a50b61b74bae Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 15 May 2016 16:03:15 +0200 Subject: [PATCH 176/400] Demo: clarified misleading example (#660) --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3961b220..c252324f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2440,7 +2440,7 @@ static void ShowExampleAppLongText(bool* p_open) { // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); - ImGuiListClipper clipper(lines, ImGui::GetTextLineHeight()); + ImGuiListClipper clipper(lines, ImGui::GetTextLineHeightWithSpacing()); // Here we changed spacing is zero anyway so we could use GetTextLineHeight(), but _WithSpacing() is typically more correct for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i); clipper.End(); From 339e191c53b7ce025e5e0fa049ad24e7a4d42c9d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 15 May 2016 18:08:41 +0200 Subject: [PATCH 177/400] Demo: Console: Add a "Scroll to bottom" button (#662) --- imgui_demo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c252324f..fa4f026d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2002,7 +2002,8 @@ struct ExampleAppConsole if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); if (ImGui::SmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); ImGui::SameLine(); - if (ImGui::SmallButton("Clear")) ClearLog(); + if (ImGui::SmallButton("Clear")) ClearLog(); ImGui::SameLine(); + if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true; //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } ImGui::Separator(); From 790275eae234bcaef1c94dcc6d54ab6090671f68 Mon Sep 17 00:00:00 2001 From: Trezanik Date: Mon, 16 May 2016 01:02:09 +0100 Subject: [PATCH 178/400] Example: DirectX9: Backup and restore all state --- examples/directx9_example/imgui_impl_dx9.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 3db8c8c9..ba67d026 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -58,14 +58,10 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) return; } - // Backup some DX9 state (not all!) - // FIXME: Backup/restore everything else - D3DRENDERSTATETYPE last_render_state_to_backup[] = { D3DRS_CULLMODE, D3DRS_LIGHTING, D3DRS_ZENABLE, D3DRS_ALPHABLENDENABLE, D3DRS_ALPHATESTENABLE, D3DRS_BLENDOP, D3DRS_SRCBLEND, D3DRS_DESTBLEND, D3DRS_SCISSORTESTENABLE }; - DWORD last_render_state_values[ARRAYSIZE(last_render_state_to_backup)] = { 0 }; - IDirect3DPixelShader9* last_ps; g_pd3dDevice->GetPixelShader( &last_ps ); - IDirect3DVertexShader9* last_vs; g_pd3dDevice->GetVertexShader( &last_vs ); - for (int n = 0; n < ARRAYSIZE(last_render_state_to_backup); n++) - g_pd3dDevice->GetRenderState(last_render_state_to_backup[n], &last_render_state_values[n]); + // Backup the DX9 state + IDirect3DStateBlock9* d3d9_state_block = NULL; + if ( g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0 ) + return; // Copy and convert all vertices into a single contiguous buffer CUSTOMVERTEX* vtx_dst; @@ -161,11 +157,9 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) vtx_offset += cmd_list->VtxBuffer.size(); } - // Restore some modified DX9 state (not all!) - g_pd3dDevice->SetPixelShader( last_ps ); - g_pd3dDevice->SetVertexShader( last_vs ); - for (int n = 0; n < ARRAYSIZE(last_render_state_to_backup); n++) - g_pd3dDevice->SetRenderState(last_render_state_to_backup[n], last_render_state_values[n]); + // Restore the DX9 state + d3d9_state_block->Apply(); + d3d9_state_block->Release(); } IMGUI_API LRESULT ImGui_ImplDX9_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 1349d0aacf7b4d150def92ff18a2156dd8ec93cb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 10:54:52 +0200 Subject: [PATCH 179/400] Examples: DirectX9: Removing spaces (#663) --- examples/directx9_example/imgui_impl_dx9.cpp | 52 ++++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index ba67d026..bb309a86 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -60,7 +60,7 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) // Backup the DX9 state IDirect3DStateBlock9* d3d9_state_block = NULL; - if ( g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0 ) + if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) return; // Copy and convert all vertices into a single contiguous buffer @@ -90,30 +90,30 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) } g_pVB->Unlock(); g_pIB->Unlock(); - g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); - g_pd3dDevice->SetIndices( g_pIB ); - g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); + g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX)); + g_pd3dDevice->SetIndices(g_pIB); + g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing - g_pd3dDevice->SetPixelShader( NULL ); - g_pd3dDevice->SetVertexShader( NULL ); - g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); - g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false ); - g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false ); - g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); - g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, false ); - g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); - g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); - g_pd3dDevice->SetRenderState( D3DRS_SCISSORTESTENABLE, true ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); - g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); - g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); - g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); + g_pd3dDevice->SetPixelShader(NULL); + g_pd3dDevice->SetVertexShader(NULL); + g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false); + g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); + g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true); + g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false); + g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); // Setup orthographic projection matrix // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() @@ -148,9 +148,9 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) else { const RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; - g_pd3dDevice->SetTexture( 0, (LPDIRECT3DTEXTURE9)pcmd->TextureId ); - g_pd3dDevice->SetScissorRect( &r ); - g_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, vtx_offset, 0, (UINT)cmd_list->VtxBuffer.size(), idx_offset, pcmd->ElemCount/3 ); + g_pd3dDevice->SetTexture(0, (LPDIRECT3DTEXTURE9)pcmd->TextureId); + g_pd3dDevice->SetScissorRect(&r); + g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vtx_offset, 0, (UINT)cmd_list->VtxBuffer.size(), idx_offset, pcmd->ElemCount/3); } idx_offset += pcmd->ElemCount; } From fa5ae60bceb40c107582f92153675000354febb4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 12:05:26 +0200 Subject: [PATCH 180/400] Demo: added decorated label to some vertical sliders. --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fa4f026d..6c311c90 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -704,7 +704,7 @@ void ImGui::ShowTestWindow(bool* p_open) if (i > 0) ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); - ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f"); + ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); ImGui::PopStyleVar(); ImGui::PopID(); } From 7a28f5bb818bf033315df96a190f4119ff123c19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 19:22:51 +0200 Subject: [PATCH 181/400] ImGuiListClipper new version, detect height automatically, fix compatibility with SetScrollPosHere (#662) --- imgui.cpp | 155 ++++++++++++++++++++++++++++++++++++------------- imgui.h | 44 +++++++------- imgui_demo.cpp | 31 ++++++---- 3 files changed, 156 insertions(+), 74 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5680cc04..6db38d71 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1607,6 +1607,88 @@ float ImGuiSimpleColumns::CalcExtraSpace(float avail_w) return ImMax(0.0f, avail_w - Width); } +//----------------------------------------------------------------------------- +// ImGuiListClipper +//----------------------------------------------------------------------------- + +static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) +{ + // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage. + // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + ImGui::SetCursorPosY(pos_y); + ImGuiWindow* window = ImGui::GetCurrentWindow(); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; + window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); +} + +// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 +// Use case B: Begin() called from constructor with items_height>0 +// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. +void ImGuiListClipper::Begin(int count, float items_height) +{ + StartPosY = ImGui::GetCursorPosY(); + ItemsHeight = items_height; + ItemsCount = count; + StepNo = 0; + DisplayEnd = DisplayStart = -1; + if (ItemsHeight > 0.0f) + { + ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display + if (DisplayStart > 0) + SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor + StepNo = 2; + } +} + +void ImGuiListClipper::End() +{ + if (ItemsCount < 0) + return; + float cur_y = ImGui::GetCursorPosY(); (void)cur_y; + float expected_display_end_y = StartPosY + DisplayEnd * ItemsHeight; + IM_ASSERT(fabsf(cur_y - expected_display_end_y) < 1.0f); // if this triggers, it probably means your items have varying height (in which case you can't use this helper) or the explicit height you have passed was incorrect. + if (ItemsCount < INT_MAX) + SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor + ItemsCount = -1; + StepNo = 3; +} + +bool ImGuiListClipper::Step() +{ + if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems) + { + ItemsCount = -1; + return false; + } + if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. + { + DisplayStart = 0; + DisplayEnd = 1; + StartPosY = ImGui::GetCursorPosY(); + StepNo = 1; + return true; + } + if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. + { + if (ItemsCount == 1) { ItemsCount = -1; return false; } + float items_height = ImGui::GetCursorPosY() - StartPosY; + IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically + ImGui::SetCursorPosY(StartPosY); // Rewind cursor so we can Begin() again, this time with a known height. + Begin(ItemsCount, items_height); + StepNo = 3; + return true; + } + if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. + { + IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0); + StepNo = 3; + return true; + } + if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. + End(); + return false; +} + //----------------------------------------------------------------------------- // ImGuiWindow //----------------------------------------------------------------------------- @@ -2878,18 +2960,8 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex } // Helper to calculate coarse clipping of large list of evenly sized items. -// NB: Prefer using the ImGuiListClipper higher-level helper if you can! +// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX -// If you are displaying thousands of items and you have a random access to the list, you can perform clipping yourself to save on CPU. -// { -// float item_height = ImGui::GetTextLineHeightWithSpacing(); -// int display_start, display_end; -// ImGui::CalcListClipping(count, item_height, &display_start, &display_end); // calculate how many to clip/display -// ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (display_start) * item_height); // advance cursor -// for (int i = display_start; i < display_end; i++) // display only visible items -// // TODO: display visible item -// ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (count - display_end) * item_height); // advance cursor -// } void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) { ImGuiContext& g = *GImGui; @@ -2901,6 +2973,11 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items *out_items_display_end = items_count; return; } + if (window->SkipItems) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } const ImVec2 pos = window->DC.CursorPos; int start = (int)((window->ClipRect.Min.y - pos.y) / items_height); @@ -8492,22 +8569,22 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. bool value_changed = false; ImGuiListClipper clipper(items_count, ImGui::GetTextLineHeightWithSpacing()); - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) - { - const bool item_selected = (i == *current_item); - const char* item_text; - if (!items_getter(data, i, &item_text)) - item_text = "*Unknown item*"; - - ImGui::PushID(i); - if (ImGui::Selectable(item_text, item_selected)) + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - *current_item = i; - value_changed = true; + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + + ImGui::PushID(i); + if (ImGui::Selectable(item_text, item_selected)) + { + *current_item = i; + value_changed = true; + } + ImGui::PopID(); } - ImGui::PopID(); - } - clipper.End(); ImGui::ListBoxFooter(); return value_changed; } @@ -9520,22 +9597,22 @@ void ImGui::ShowMetricsWindow(bool* p_open) } if (!pcmd_node_open) continue; - ImGuiListClipper clipper(pcmd->ElemCount/3, ImGui::GetTextLineHeight()*3 + ImGui::GetStyle().ItemSpacing.y); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) - { - char buf[300], *buf_p = buf; - ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + while (clipper.Step()) + for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; - triangles_pos[n] = v.pos; - buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + char buf[300], *buf_p = buf; + ImVec2 triangles_pos[3]; + for (int n = 0; n < 3; n++, vtx_i++) + { + ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + triangles_pos[n] = v.pos; + buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + ImGui::Selectable(buf, false); + if (ImGui::IsItemHovered()) + overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle } - ImGui::Selectable(buf, false); - if (ImGui::IsItemHovered()) - overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle - } - clipper.End(); ImGui::TreePop(); } overlay_draw_list->PopClipRect(); diff --git a/imgui.h b/imgui.h index c201b077..c6618c58 100644 --- a/imgui.h +++ b/imgui.h @@ -1049,36 +1049,32 @@ struct ImColor }; // Helper: Manually clip large list of items. -// If you are displaying thousands of even spaced items and you have a random access to the list, you can perform clipping yourself to save on CPU. +// If you are displaying thousands of evenly spaced items and you have a random access to the list, you can perform clipping yourself to save on CPU. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. // Usage: -// ImGuiListClipper clipper(count, ImGui::GetTextLineHeightWithSpacing()); -// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // display only visible items -// ImGui::Text("line number %d", i); -// clipper.End(); -// NB: 'count' is only used to clamp the result, if you don't know your count you can use INT_MAX +// ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. +// - Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. +// - Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. +// - Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. struct ImGuiListClipper { + float StartPosY; float ItemsHeight; - int ItemsCount, DisplayStart, DisplayEnd; + int ItemsCount, StepNo, DisplayStart, DisplayEnd; - ImGuiListClipper() { ItemsHeight = 0.0f; ItemsCount = DisplayStart = DisplayEnd = -1; } - ImGuiListClipper(int count, float height) { ItemsCount = -1; Begin(count, height); } - ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // user forgot to call End() + // items_count: Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step). + // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing(). + // If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step(). + ImGuiListClipper(int items_count = -1, float items_height = -1.0f) { Begin(items_count, items_height); } // NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want). + ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // Assert if user forgot to call End() or Step() until false. - void Begin(int count, float height) // items_height: generally pass GetTextLineHeightWithSpacing() or GetItemsLineHeightWithSpacing() - { - IM_ASSERT(ItemsCount == -1); - ItemsCount = count; - ItemsHeight = height; - ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + DisplayStart * ItemsHeight); // advance cursor - } - void End() - { - IM_ASSERT(ItemsCount >= 0); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (ItemsCount - DisplayEnd) * ItemsHeight); // advance cursor - ItemsCount = -1; - } + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. + IMGUI_API void Begin(int items_count, float items_height = -1.0f); // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1. + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. }; //----------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6c311c90..9ff0cb16 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2014,24 +2014,33 @@ struct ExampleAppConsole ImGui::PopStyleVar(); ImGui::Separator(); - // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); - // NB- if you have thousands of entries this approach may be too inefficient. You can seek and display only the lines that are visible - CalcListClipping() is a helper to compute this information. - // If your items are of variable size you may want to implement code similar to what CalcListClipping() does. Or split your data into fixed height items to allow random-seeking into your list. ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetItemsLineHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar); if (ImGui::BeginPopupContextWindow()) { if (ImGui::Selectable("Clear")) ClearLog(); ImGui::EndPopup(); } + + // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items. + // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements. + // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with: + // ImGuiListClipper clipper(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // However take note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code! + // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list. ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing for (int i = 0; i < Items.Size; i++) { const char* item = Items[i]; if (!filter.PassFilter(item)) continue; - ImVec4 col = ImColor(255,255,255); // A better implementation may store a type per-item. For the sample let's just parse the text. - if (strstr(item, "[error]")) col = ImColor(255,100,100); - else if (strncmp(item, "# ", 2) == 0) col = ImColor(255,200,150); + ImVec4 col = ImVec4(1.0f,1.0f,1.0f,1.0f); // A better implementation may store a type per-item. For the sample let's just parse the text. + if (strstr(item, "[error]")) col = ImColor(1.0f,0.4f,0.4f,1.0f); + else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f,0.78f,0.58f,1.0f); ImGui::PushStyleColor(ImGuiCol_Text, col); ImGui::TextUnformatted(item); ImGui::PopStyleColor(); @@ -2441,10 +2450,10 @@ static void ShowExampleAppLongText(bool* p_open) { // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); - ImGuiListClipper clipper(lines, ImGui::GetTextLineHeightWithSpacing()); // Here we changed spacing is zero anyway so we could use GetTextLineHeight(), but _WithSpacing() is typically more correct - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) - ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i); - clipper.End(); + ImGuiListClipper clipper(lines); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); ImGui::PopStyleVar(); break; } @@ -2452,7 +2461,7 @@ static void ShowExampleAppLongText(bool* p_open) // Multiple calls to Text(), not clipped (slow) ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); for (int i = 0; i < lines; i++) - ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i); + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); ImGui::PopStyleVar(); break; } From 28b09199de92c4e1b7e15c4797b2c4243909f4ea Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 19:25:42 +0200 Subject: [PATCH 182/400] ImGuiListClipper: removed assert (#662) --- imgui.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6db38d71..27c88caa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1644,9 +1644,7 @@ void ImGuiListClipper::End() { if (ItemsCount < 0) return; - float cur_y = ImGui::GetCursorPosY(); (void)cur_y; - float expected_display_end_y = StartPosY + DisplayEnd * ItemsHeight; - IM_ASSERT(fabsf(cur_y - expected_display_end_y) < 1.0f); // if this triggers, it probably means your items have varying height (in which case you can't use this helper) or the explicit height you have passed was incorrect. + // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. if (ItemsCount < INT_MAX) SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor ItemsCount = -1; From f291f2c5dd65b5ae7e96c7dc34944fd55be82e0e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 19:44:03 +0200 Subject: [PATCH 183/400] InputText(): Fixed cursor rendering on first character when framepadding is 0.0 (following #601) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 27c88caa..02d8b730 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8034,9 +8034,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Draw blinking cursor bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f; ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll; - ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x, cursor_screen_pos.y-1.5f); + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x+1.0f, cursor_screen_pos.y-1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) - draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.Max, GetColorU32(ImGuiCol_Text)); + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (is_editable) From 787be01e61c407937ffc3482cbaa29dd6a21885e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 20:03:18 +0200 Subject: [PATCH 184/400] ImGuiListClipper comments (#660, #661, #662) --- imgui.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui.h b/imgui.h index c6618c58..37621762 100644 --- a/imgui.h +++ b/imgui.h @@ -1049,16 +1049,17 @@ struct ImColor }; // Helper: Manually clip large list of items. -// If you are displaying thousands of evenly spaced items and you have a random access to the list, you can perform clipping yourself to save on CPU. -// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse clipping based on visibility to save yourself from processing those items at all. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// ImGui already clip items based on their bounds but it needs to measure text size to do so. Coarse clipping before submission makes this cost and your own data fetching/submission cost null. // Usage: // ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced. // while (clipper.Step()) // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // ImGui::Text("line number %d", i); -// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. +// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height (step skipped if we passed a known height as second arg to constructor). // - Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. -// - Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. +// - (Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user call Step(). Does nothing and switch to Step 3.) // - Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. struct ImGuiListClipper { From 47d10944a59284faf86146b3d1fb30ff91723e96 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 20:07:02 +0200 Subject: [PATCH 185/400] Build fix --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 02d8b730..6ee82661 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1645,7 +1645,7 @@ void ImGuiListClipper::End() if (ItemsCount < 0) return; // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. - if (ItemsCount < INT_MAX) + if (ItemsCount < IM_INT_MAX) SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor ItemsCount = -1; StepNo = 3; From 69a29e4715d463e22a58bb0766275168efa1586a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 20:14:07 +0200 Subject: [PATCH 186/400] Added NewLine() (very shy reminder that #97 isn't done) --- imgui.cpp | 11 +++++++++++ imgui.h | 1 + imgui_demo.cpp | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6ee82661..822edcb9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9122,6 +9122,17 @@ void ImGui::SameLine(float pos_x, float spacing_w) window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; } +void ImGui::NewLine() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + if (window->DC.CurrentLineHeight > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + ItemSize(ImVec2(0,0)); + else + ItemSize(ImVec2(0.0f, GImGui->FontSize)); +} + void ImGui::NextColumn() { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui.h b/imgui.h index 37621762..7697e120 100644 --- a/imgui.h +++ b/imgui.h @@ -191,6 +191,7 @@ namespace ImGui // Cursor / Layout IMGUI_API void Separator(); // horizontal line IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally + IMGUI_API void NewLine(); // undo a SameLine() IMGUI_API void Spacing(); // add spacing IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9ff0cb16..c5f90a28 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -384,14 +384,14 @@ void ImGui::ShowTestWindow(bool* p_open) static int pressed_count = 0; for (int i = 0; i < 8; i++) { - if (i > 0) - ImGui::SameLine(); ImGui::PushID(i); int frame_padding = -1 + i; // -1 = uses default padding if (ImGui::ImageButton(tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/tex_w,32/tex_h), frame_padding, ImColor(0,0,0,255))) pressed_count += 1; ImGui::PopID(); + ImGui::SameLine(); } + ImGui::NewLine(); ImGui::Text("Pressed %d times.", pressed_count); ImGui::TreePop(); } From 0e51f91c5e46e8935cf653507b7a2406c8b1524a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 May 2016 20:27:52 +0200 Subject: [PATCH 187/400] Including limits.h again to get INT_MAX, assuming previous report of missing limits.h was erroneous (#1, yes, issue ONE!) --- imgui.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 822edcb9..d920b6e5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -611,6 +611,7 @@ #include // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf #include // NULL, malloc, free, qsort, atoi #include // vsnprintf, sscanf, printf +#include // INT_MIN, INT_MAX #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #include // intptr_t #else @@ -863,9 +864,6 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) #define IM_F32_TO_INT8(_VAL) ((int)((_VAL) * 255.0f + 0.5f)) -#define IM_INT_MIN (-2147483647-1) -#define IM_INT_MAX (2147483647) - // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. #ifdef _WIN32 #define IM_NEWLINE "\r\n" @@ -1645,7 +1643,7 @@ void ImGuiListClipper::End() if (ItemsCount < 0) return; // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. - if (ItemsCount < IM_INT_MAX) + if (ItemsCount < INT_MAX) SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor ItemsCount = -1; StepNo = 3; @@ -1735,8 +1733,8 @@ ImGuiWindow::ImGuiWindow(const char* name) ParentWindow = NULL; FocusIdxAllCounter = FocusIdxTabCounter = -1; - FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = IM_INT_MAX; - FocusIdxAllRequestNext = FocusIdxTabRequestNext = IM_INT_MAX; + FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX; + FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX; } ImGuiWindow::~ImGuiWindow() @@ -1900,7 +1898,7 @@ bool ImGui::FocusableItemRegister(ImGuiWindow* window, bool is_active, bool tab_ // Process keyboard input at this point: TAB, Shift-TAB switch focus // We can always TAB out of a widget that doesn't allow tabbing in. - if (tab_stop && window->FocusIdxAllRequestNext == IM_INT_MAX && window->FocusIdxTabRequestNext == IM_INT_MAX && is_active && IsKeyPressedMap(ImGuiKey_Tab)) + if (tab_stop && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && is_active && IsKeyPressedMap(ImGuiKey_Tab)) { // Modulo on index will be applied at the end of frame once we've got the total counter of items. window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); @@ -4050,10 +4048,10 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f); // Prepare for focus requests - window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == IM_INT_MAX || window->FocusIdxAllCounter == -1) ? IM_INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); - window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == IM_INT_MAX || window->FocusIdxTabCounter == -1) ? IM_INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); + window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1); + window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1); window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; - window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; + window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX; // Apply scrolling if (window->ScrollTarget.x < FLT_MAX) @@ -5147,7 +5145,7 @@ void ImGui::SetKeyboardFocusHere(int offset) { ImGuiWindow* window = GetCurrentWindow(); window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset; - window->FocusIdxTabRequestNext = IM_INT_MAX; + window->FocusIdxTabRequestNext = INT_MAX; } void ImGui::SetStateStorage(ImGuiStorage* tree) @@ -6936,10 +6934,10 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ ImGui::BeginGroup(); PushMultiItemsWidths(2); - bool value_changed = ImGui::DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? IM_INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format); + bool value_changed = ImGui::DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format); ImGui::PopItemWidth(); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= ImGui::DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? IM_INT_MAX : v_max, display_format_max ? display_format_max : display_format); + value_changed |= ImGui::DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, display_format_max ? display_format_max : display_format); ImGui::PopItemWidth(); ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); From 1dfafeb602fd3afbba5d73a997ab6d89d38d9038 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 May 2016 09:36:27 +0200 Subject: [PATCH 188/400] CheckStacksSize() added literal strings in IM_ASSERT calls to reach end-user on common failure --- imgui.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d920b6e5..44f9927a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3617,12 +3617,12 @@ static void CheckStacksSize(ImGuiWindow* window, bool write) // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) ImGuiContext& g = *GImGui; int* p_backup = &window->DC.StackSizesBackup[0]; - { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopID() - { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot EndGroup() - { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot EndPopup()/EndMenu() - { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopStyleColor() - { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopStyleVar() - { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current); p_backup++; } // User forgot PopFont() + { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID Mismatch!"); p_backup++; } // User forgot PopID() + { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // User forgot EndGroup() + { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++; }// User forgot EndPopup()/EndMenu() + { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // User forgot PopStyleColor() + { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // User forgot PopStyleVar() + { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushFont/PopFont Mismatch!"); p_backup++; } // User forgot PopFont() IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); } From b4302187dd0e93e905d4319297e7b35868839590 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 May 2016 19:47:13 +0200 Subject: [PATCH 189/400] ImFontAtlas: Tweak to allow MergeMode to apply on a font that isn't the previous one, by setting the DstFont field. --- imgui_draw.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 57b13bf8..9f3c265b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1141,7 +1141,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) ConfigData.push_back(*font_cfg); ImFontConfig& new_font_cfg = ConfigData.back(); - new_font_cfg.DstFont = Fonts.back(); + if (!new_font_cfg.DstFont) + new_font_cfg.DstFont = Fonts.back(); if (!new_font_cfg.FontDataOwnedByAtlas) { new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize); @@ -1151,7 +1152,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Invalidate texture ClearTexData(); - return Fonts.back(); + return new_font_cfg.DstFont; } // Default font TTF is compressed with stb_compress then base85 encoded (see extra_fonts/binary_to_compressed_c.cpp for encoder) From 47911d92b2ccb496bb8de3ddca831e34b141abca Mon Sep 17 00:00:00 2001 From: Jeongseok Lee Date: Fri, 20 May 2016 07:04:54 -0400 Subject: [PATCH 190/400] Fix minor typo in examples/README.txt --- examples/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.txt b/examples/README.txt index df6fe879..df2e86da 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -71,7 +71,7 @@ apple_example/ sdl_opengl_example/ SDL2 + OpenGL example. -sdl_opengl_example/ +sdl_opengl3_example/ SDL2 + OpenGL3 example. allegro5_example/ From 81bf5aeb09cd5cb45fc43711a7f33ef518b5cf21 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 20:07:51 +0200 Subject: [PATCH 191/400] Minor bits --- imgui.cpp | 8 ++++---- imgui.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 44f9927a..2dfa2317 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3796,7 +3796,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us bool window_pos_set_by_api = false, window_size_set_by_api = false; if (g.SetNextWindowPosCond) { - const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this anymore :( need to look into that. + const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this saving/restore anymore :( need to look into that. if (!window_was_active || window_appearing_after_being_hidden) window->SetWindowPosAllowFlags |= ImGuiSetCond_Appearing; window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.SetNextWindowPosCond) != 0; if (window_pos_set_by_api && ImLengthSqr(g.SetNextWindowPosVal - ImVec2(-FLT_MAX,-FLT_MAX)) < 0.001f) @@ -3857,12 +3857,12 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->Active = true; window->IndexWithinParent = 0; window->BeginCount = 0; - window->DrawList->Clear(); window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); window->LastFrameActive = current_frame; window->IDStack.resize(1); - // Setup texture, outer clipping rectangle + // Clear draw list, setup texture, outer clipping rectangle + window->DrawList->Clear(); window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); ImRect fullscreen_rect(GetVisibleRect()); if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ComboBox|ImGuiWindowFlags_Popup))) @@ -4438,7 +4438,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) // Steal focus on active widgets if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) - ImGui::SetActiveID(0); + SetActiveID(0); // Bring to front if ((window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) || g.Windows.back() == window) diff --git a/imgui.h b/imgui.h index 7697e120..71782c7b 100644 --- a/imgui.h +++ b/imgui.h @@ -250,7 +250,7 @@ namespace ImGui IMGUI_API void BulletText(const char* fmt, ...) IM_PRINTFARGS(1); IMGUI_API void BulletTextV(const char* fmt, va_list args); IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); - IMGUI_API bool SmallButton(const char* label); + IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); 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 From 102d03a7eb09e6eb8f4bfdc3df41edae03b74d04 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 20:50:15 +0200 Subject: [PATCH 192/400] Resizing window doesn't rely on MouseDelta anymore, but rather recompute expected size based absolute mouse coords. (#668) Storing ActiveIdClickOffset to generalize pattern already used by columns. --- imgui.cpp | 10 ++++++---- imgui_demo.cpp | 4 +--- imgui_internal.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2dfa2317..58e41fac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3993,7 +3993,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) { window->Pos = window->PosFloat = parent_window->DC.CursorPos; - window->Size = window->SizeFull = size_on_first_use; // NB: argument name 'size_on_first_use' misleading here, it's really just 'size' as provided by user. + window->Size = window->SizeFull = size_on_first_use; // NB: argument name 'size_on_first_use' misleading here, it's really just 'size' as provided by user passed via BeginChild()->Begin(). } bool window_pos_center = false; @@ -4108,7 +4108,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us } else if (held) { - window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); + // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position + window->SizeFull = ImMax((g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize()) - window->Pos, style.WindowMinSize); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } @@ -5423,6 +5424,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { SetActiveID(id, window); // Hold on ID FocusWindow(window); + g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; } if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0])) { @@ -9188,7 +9190,7 @@ static float GetDraggedColumnOffset(int column_index) IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets. IM_ASSERT(g.ActiveId == window->DC.ColumnsSetID + ImGuiID(column_index)); - float x = g.IO.MousePos.x + g.ActiveClickDeltaToCenter.x - window->Pos.x; + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x; x = ImClamp(x, ImGui::GetColumnOffset(column_index-1)+g.Style.ColumnsMinSpacing, ImGui::GetColumnOffset(column_index+1)-g.Style.ColumnsMinSpacing); return (float)(int)x; @@ -9293,7 +9295,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) if (held) { if (g.ActiveIdIsJustActivated) - g.ActiveClickDeltaToCenter.x = x - g.IO.MousePos.x; + g.ActiveIdClickOffset.x -= 4; // Store from center of column line x = GetDraggedColumnOffset(i); SetColumnOffset(i, x); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c5f90a28..c77adc9b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1807,10 +1807,8 @@ static void ShowExampleAppFixedOverlay(bool* p_open) ImGui::End(); } -static void ShowExampleAppManipulatingWindowTitle(bool* p_open) +static void ShowExampleAppManipulatingWindowTitle(bool*) { - (void)p_open; - // By default, Windows are uniquely identified by their title. // You can use the "##" and "###" markers to manipulate the display/ID. Read FAQ at the top of this file! diff --git a/imgui_internal.h b/imgui_internal.h index 6c90e53a..b4db7228 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -373,6 +373,7 @@ struct ImGuiContext bool ActiveIdIsAlive; bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Set only by active widget + ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. ImGuiID MovedWindowMoveId; // == MovedWindow->RootWindow->MoveId @@ -410,7 +411,6 @@ struct ImGuiContext ImFont InputTextPasswordFont; ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode - ImVec2 ActiveClickDeltaToCenter; float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings ImVec2 DragLastMouseDelta; float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio @@ -458,6 +458,7 @@ struct ImGuiContext ActiveIdIsAlive = false; ActiveIdIsJustActivated = false; ActiveIdAllowOverlap = false; + ActiveIdClickOffset = ImVec2(-1,-1); ActiveIdWindow = NULL; MovedWindow = NULL; MovedWindowMoveId = 0; @@ -475,7 +476,6 @@ struct ImGuiContext SetNextTreeNodeOpenCond = 0; ScalarAsInputTextId = 0; - ActiveClickDeltaToCenter = ImVec2(0.0f, 0.0f); DragCurrentValue = 0.0f; DragLastMouseDelta = ImVec2(0.0f, 0.0f); DragSpeedDefaultRatio = 0.01f; From 713730af0c79d11ff2d431dcb66dc54ff10a4ad0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 20:55:28 +0200 Subject: [PATCH 193/400] Minor sizing refactor, should be no-op. Making it a commit for further bisection since sizing code is super brittle. (#668) --- imgui.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 58e41fac..8ac23977 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3953,7 +3953,6 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; if (window->AutoFitFramesY > 0) window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; - window->Size = window->TitleBarRect().GetSize(); } else { @@ -3971,17 +3970,13 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } - window->Size = window->SizeFull; } - // Minimum window size + // Apply window size constraints and final size if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) - { window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); - if (!window->Collapsed) - window->Size = window->SizeFull; - } - + window->Size = window->Collapsed ? window->TitleBarRect().GetSize() : window->SizeFull; + // POSITION // Position child window From 753bf5cefef87f7e1c5240a8b86004b3f431eff9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 22:35:05 +0200 Subject: [PATCH 194/400] Comments --- imgui.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index 71782c7b..3b624d08 100644 --- a/imgui.h +++ b/imgui.h @@ -1030,6 +1030,7 @@ struct ImGuiTextEditCallbackData }; // ImColor() helper to implicity converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) +// Prefer using IM_COL32() macros if you want a guaranteed compile-time ImU32 for usage with ImDrawList API. // Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. // None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. struct ImColor @@ -1092,12 +1093,8 @@ struct ImGuiListClipper // Draw callbacks for advanced uses. // NB- You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering (you can poke into the draw list for that) -// Draw callback may be useful for example, if you want to render a complex 3D scene inside a UI element, change your GPU render state, etc. -// The expected behavior from your rendering loop is: -// if (cmd.UserCallback != NULL) -// cmd.UserCallback(parent_list, cmd); -// else -// RenderTriangles() +// Draw callback may be useful for example, A) Change your GPU render state, B) render a complex 3D scene inside a UI element (without an intermediate texture/render target), etc. +// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) cmd.UserCallback(parent_list, cmd); else RenderTriangles()' typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); // Typically, 1 command = 1 gpu draw call (unless command is a callback) @@ -1112,7 +1109,7 @@ struct ImDrawCmd ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = -8192.0f; ClipRect.z = ClipRect.w = +8192.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; } }; -// Vertex index (override with, e.g. '#define ImDrawIdx unsigned int' in ImConfig) +// Vertex index (override with '#define ImDrawIdx unsigned int' inside in imconfig.h) #ifndef ImDrawIdx typedef unsigned short ImDrawIdx; #endif From b7ebeb1610d27868b78206bf28cf5b5f7ee68013 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 22:53:08 +0200 Subject: [PATCH 195/400] Added SetNextWindowSizeConstraint() + demo code (#668) --- imgui.cpp | 48 +++++++++++++++++++++++++++++++++++++++++------- imgui.h | 15 ++++++++++++++- imgui_demo.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ imgui_internal.h | 6 ++++++ 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8ac23977..6f79ef82 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -457,7 +457,6 @@ The list below consist mostly of notes of things to do before they are requested/discussed by users (at that point it usually happens on the github) - doc: add a proper documentation+regression testing system (#435) - - window: maximum window size settings (per-axis). for large popups in particular user may not want the popup to fill all space. - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). - window: auto-fit feedback loop when user relies on any dynamic layout (window width multiplier, column) appears weird to end-user. clarify. @@ -3416,7 +3415,7 @@ static inline void ClearSetNextWindowData() { ImGuiContext& g = *GImGui; g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowContentSizeCond = g.SetNextWindowCollapsedCond = 0; - g.SetNextWindowFocus = false; + g.SetNextWindowSizeConstraint = g.SetNextWindowFocus = false; } static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) @@ -3731,6 +3730,31 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl return window; } +static void ApplySizeFullWithConstraint(ImGuiWindow* window, ImVec2 new_size) +{ + ImGuiContext& g = *GImGui; + if (g.SetNextWindowSizeConstraint) + { + // Using -1,-1 on either X/Y axis to preserve the current size. + ImRect cr = g.SetNextWindowSizeConstraintRect; + new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; + new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; + if (g.SetNextWindowSizeConstraintCallback) + { + ImGuiSizeConstraintCallbackData data; + data.UserData = g.SetNextWindowSizeConstraintCallbackUserData; + data.Pos = window->Pos; + data.CurrentSize = window->SizeFull; + data.DesiredSize = new_size; + g.SetNextWindowSizeConstraintCallback(&data); + new_size = data.DesiredSize; + } + } + if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + new_size = ImMax(new_size, g.Style.WindowMinSize); + window->SizeFull = new_size; +} + // Push a new ImGui window to add widgets to. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. @@ -3972,9 +3996,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us } } - // Apply window size constraints and final size - if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) - window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); + // Apply minimum/maximum window size constraints and final size + ApplySizeFullWithConstraint(window, window->SizeFull); window->Size = window->Collapsed ? window->TitleBarRect().GetSize() : window->SizeFull; // POSITION @@ -4096,7 +4119,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) { // Manual auto-fit when double-clicking - window->SizeFull = size_auto_fit; + ApplySizeFullWithConstraint(window, size_auto_fit); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); SetActiveID(0); @@ -4104,7 +4127,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us else if (held) { // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position - window->SizeFull = ImMax((g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize()) - window->Pos, style.WindowMinSize); + ApplySizeFullWithConstraint(window, (g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize()) - window->Pos); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } @@ -4177,6 +4200,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Setup drawing context window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffsetX = 0.0f; window->DC.ColumnsOffsetX = 0.0f; window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); window->DC.CursorPos = window->DC.CursorStartPos; @@ -4268,6 +4292,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (first_begin_of_the_frame) window->Accessed = false; window->BeginCount++; + g.SetNextWindowSizeConstraint = 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). @@ -4906,6 +4931,15 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond) g.SetNextWindowSizeCond = cond ? cond : ImGuiSetCond_Always; } +void ImGui::SetNextWindowSizeConstraint(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback, void* custom_callback_user_data) +{ + ImGuiContext& g = *GImGui; + g.SetNextWindowSizeConstraint = true; + g.SetNextWindowSizeConstraintRect = ImRect(size_min, size_max); + g.SetNextWindowSizeConstraintCallback = custom_callback; + g.SetNextWindowSizeConstraintCallbackUserData = custom_callback_user_data; +} + void ImGui::SetNextWindowContentSize(const ImVec2& size) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 3b624d08..9c2cc288 100644 --- a/imgui.h +++ b/imgui.h @@ -52,7 +52,8 @@ struct ImGuiStorage; // Simple custom key value storage struct ImGuiStyle; // Runtime data for styling/colors struct ImGuiTextFilter; // Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" struct ImGuiTextBuffer; // Text buffer for logging/accumulating text -struct ImGuiTextEditCallbackData; // Shared state of ImGui::InputText() when using custom callbacks (advanced) +struct ImGuiTextEditCallbackData; // Shared state of ImGui::InputText() when using custom ImGuiTextEditCallback (rare/advanced use) +struct ImGuiSizeConstraintCallbackData;// Structure used to constraint window size in custom ways when using custom ImGuiSizeConstraintCallback (rare/advanced use) struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiContext; // ImGui context (opaque) @@ -73,6 +74,7 @@ typedef int ImGuiInputTextFlags; // flags for InputText*() // e typedef int ImGuiSelectableFlags; // flags for Selectable() // enum ImGuiSelectableFlags_ typedef int ImGuiTreeNodeFlags; // flags for TreeNode*(), Collapsing*() // enum ImGuiTreeNodeFlags_ typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); +typedef void (*ImGuiSizeConstraintCallback)(ImGuiSizeConstraintCallbackData* data); // Others helpers at bottom of the file: // class ImVector<> // Lightweight std::vector like class. @@ -138,6 +140,7 @@ namespace ImGui IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position. call before Begin() IMGUI_API void SetNextWindowPosCenter(ImGuiSetCond cond = 0); // set next window position to be centered on screen. call before Begin() IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() + IMGUI_API void SetNextWindowSizeConstraint(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (enforce the range of scrollbars). set axis to 0.0f to leave it automatic. call before Begin() IMGUI_API void SetNextWindowContentWidth(float width); // set next window content width (enforce the range of horizontal scrollbar). call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. call before Begin() @@ -1029,6 +1032,16 @@ struct ImGuiTextEditCallbackData bool HasSelection() const { return SelectionStart != SelectionEnd; } }; +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraint(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraint() parameters are enough. +struct ImGuiSizeConstraintCallbackData +{ + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraint() + ImVec2 Pos; // Read-only. Window position, for reference. + ImVec2 CurrentSize; // Read-only. Current window size. + ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. +}; + // ImColor() helper to implicity converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) // Prefer using IM_COL32() macros if you want a guaranteed compile-time ImU32 for usage with ImDrawList API. // Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c77adc9b..242ea707 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -46,6 +46,7 @@ #endif #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) +#define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B)) //----------------------------------------------------------------------------- // DEMO CODE @@ -59,6 +60,7 @@ static void ShowExampleAppLayout(bool* p_open); static void ShowExampleAppPropertyEditor(bool* p_open); static void ShowExampleAppLongText(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open); +static void ShowExampleAppConstrainedResize(bool* p_open); static void ShowExampleAppFixedOverlay(bool* p_open); static void ShowExampleAppManipulatingWindowTitle(bool* p_open); static void ShowExampleAppCustomRendering(bool* p_open); @@ -105,6 +107,7 @@ void ImGui::ShowTestWindow(bool* p_open) static bool show_app_property_editor = false; static bool show_app_long_text = false; static bool show_app_auto_resize = false; + static bool show_app_constrained_resize = false; static bool show_app_fixed_overlay = false; static bool show_app_manipulating_window_title = false; static bool show_app_custom_rendering = false; @@ -120,6 +123,7 @@ void ImGui::ShowTestWindow(bool* p_open) if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); + if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay); if (show_app_manipulating_window_title) ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title); if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); @@ -183,6 +187,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); ImGui::MenuItem("Long text display", NULL, &show_app_long_text); ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); + ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay); ImGui::MenuItem("Manipulating window title", NULL, &show_app_manipulating_window_title); ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); @@ -1793,6 +1798,43 @@ static void ShowExampleAppAutoResize(bool* p_open) ImGui::End(); } +static void ShowExampleAppConstrainedResize(bool* p_open) +{ + struct CustomConstraints // Helper functions to demonstrate programmatic constraints + { + static void Square(ImGuiSizeConstraintCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); } + static void Step(ImGuiSizeConstraintCallbackData* data) { float step = (float)(int)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } + }; + + static int type = 0; + if (type == 0) ImGui::SetNextWindowSizeConstraint(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only + if (type == 1) ImGui::SetNextWindowSizeConstraint(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only + if (type == 2) ImGui::SetNextWindowSizeConstraint(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 3) ImGui::SetNextWindowSizeConstraint(ImVec2(300, 0), ImVec2(400, FLT_MAX)); // Width 300-400 + if (type == 4) ImGui::SetNextWindowSizeConstraint(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 5) ImGui::SetNextWindowSizeConstraint(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step + + if (ImGui::Begin("Example: Constrained Resize", p_open)) + { + const char* desc[] = + { + "Resize vertical only", + "Resize horizontal only", + "Width > 100, Height > 100", + "Width 300-400", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + }; + ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); + if (ImGui::Button("200x200")) ImGui::SetWindowSize(ImVec2(200,200)); ImGui::SameLine(); + if (ImGui::Button("500x500")) ImGui::SetWindowSize(ImVec2(500,500)); ImGui::SameLine(); + if (ImGui::Button("800x200")) ImGui::SetWindowSize(ImVec2(800,200)); + for (int i = 0; i < 10; i++) + ImGui::Text("Hello, sailor! Making this line long enough for the example."); + } + ImGui::End(); +} + static void ShowExampleAppFixedOverlay(bool* p_open) { ImGui::SetNextWindowPos(ImVec2(10,10)); diff --git a/imgui_internal.h b/imgui_internal.h index b4db7228..c787dbd1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -394,6 +394,10 @@ struct ImGuiContext ImGuiSetCond SetNextWindowSizeCond; ImGuiSetCond SetNextWindowContentSizeCond; ImGuiSetCond SetNextWindowCollapsedCond; + ImRect SetNextWindowSizeConstraintRect; // Valid if 'SetNextWindowSizeConstraint' is true + ImGuiSizeConstraintCallback SetNextWindowSizeConstraintCallback; + void* SetNextWindowSizeConstraintCallbackUserData; + bool SetNextWindowSizeConstraint; bool SetNextWindowFocus; bool SetNextTreeNodeOpenVal; ImGuiSetCond SetNextTreeNodeOpenCond; @@ -472,6 +476,8 @@ struct ImGuiContext SetNextWindowContentSizeCond = 0; SetNextWindowCollapsedCond = 0; SetNextWindowFocus = false; + SetNextWindowSizeConstraintCallback = NULL; + SetNextWindowSizeConstraintCallbackUserData = NULL; SetNextTreeNodeOpenVal = false; SetNextTreeNodeOpenCond = 0; From 3a776d93f2beb6d36b00d555e0b249228ad0d54e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 23:03:21 +0200 Subject: [PATCH 196/400] Fixed compile issue (bloody git stashes) (#668) --- imgui.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6f79ef82..ae1e3445 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4200,7 +4200,6 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Setup drawing context window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; - window->DC.GroupOffsetX = 0.0f; window->DC.ColumnsOffsetX = 0.0f; window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); window->DC.CursorPos = window->DC.CursorStartPos; From e3d8055d90bad09f473d32768aa0419200624816 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 May 2016 23:13:11 +0200 Subject: [PATCH 197/400] Speculative 64-bit warning fix (#668) --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 242ea707..d71343b3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1803,7 +1803,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open) struct CustomConstraints // Helper functions to demonstrate programmatic constraints { static void Square(ImGuiSizeConstraintCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); } - static void Step(ImGuiSizeConstraintCallbackData* data) { float step = (float)(int)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } + static void Step(ImGuiSizeConstraintCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } }; static int type = 0; From 65b1ae6ecc2d764c0ede14a0e0c987ec633068e4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 May 2016 10:20:58 +0200 Subject: [PATCH 198/400] Comments (#335) --- imgui.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ae1e3445..45188fc3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -153,9 +153,10 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2016/05/12 (1.49) - title bar (using TitleBg/TitleBgActive colors) isn't rendered over a window background (WindowBg color) anymore. - If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. - This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given that color and the WindowBg color. + - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. + However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; @@ -578,7 +579,7 @@ - keyboard: full keyboard navigation and focus. (#323) - focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622) - focus: SetKeyboardFocusHere() on with >= 0 offset could be done on same frame (else latch and modulate on beginning of next frame) - - input: rework IO system to be able to pass actual ordered/timestamped events. + - input: rework IO system to be able to pass actual ordered/timestamped events. (~#335, #71) - input: allow to decide and pass explicit double-clicks (e.g. for windows by the CS_DBLCLKS style). - input: support track pad style scrolling & slider edit. - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) @@ -591,6 +592,7 @@ - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - examples: directx9: save/restore device state more thoroughly. - examples: window minimize, maximize (#583) + - optimization: add a flag to disable most of rendering, for the case where the user expect to skip it (#335) - optimization: use another hash function than crc32, e.g. FNV1a - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimization: turn some the various stack vectors into statically-sized arrays From 213025f3cde2a4afdb95eb016a5eb8faa2cd6cfd Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 11:14:02 +0200 Subject: [PATCH 199/400] BeginMenu: a menu that becomes disabled when open gets closed down, facilitate user's code (#126) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 45188fc3..072f2dcf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8778,7 +8778,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues - tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); moving_within_opened_triangle = ImIsPointInTriangle(g.IO.MousePos, ta, tb, tc); //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? 0x80008000 : 0x80000080); window->DrawList->PopClipRect(); // Debug @@ -8795,7 +8795,8 @@ bool ImGui::BeginMenu(const char* label, bool enabled) } else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // menu-bar: first click to open, then hover to open others want_open = true; - + if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' + want_close = true; if (want_close && IsPopupOpen(id)) ClosePopupToLevel(GImGui->CurrentPopupStack.Size); From 8f4b123e1bf08314d071444b1260148c75448397 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 14:02:14 +0200 Subject: [PATCH 200/400] SetNextWindowSizeConstraint -> SetNextWindowSizeConstraints (#668) --- imgui.cpp | 2 +- imgui.h | 8 ++++---- imgui_demo.cpp | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 072f2dcf..d677f2a6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4932,7 +4932,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond) g.SetNextWindowSizeCond = cond ? cond : ImGuiSetCond_Always; } -void ImGui::SetNextWindowSizeConstraint(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback, void* custom_callback_user_data) +void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback, void* custom_callback_user_data) { ImGuiContext& g = *GImGui; g.SetNextWindowSizeConstraint = true; diff --git a/imgui.h b/imgui.h index 9c2cc288..bc5fd2b6 100644 --- a/imgui.h +++ b/imgui.h @@ -140,7 +140,7 @@ namespace ImGui IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position. call before Begin() IMGUI_API void SetNextWindowPosCenter(ImGuiSetCond cond = 0); // set next window position to be centered on screen. call before Begin() IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() - IMGUI_API void SetNextWindowSizeConstraint(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. + IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (enforce the range of scrollbars). set axis to 0.0f to leave it automatic. call before Begin() IMGUI_API void SetNextWindowContentWidth(float width); // set next window content width (enforce the range of horizontal scrollbar). call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. call before Begin() @@ -1032,11 +1032,11 @@ struct ImGuiTextEditCallbackData bool HasSelection() const { return SelectionStart != SelectionEnd; } }; -// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraint(). Callback is called during the next Begin(). -// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraint() parameters are enough. +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. struct ImGuiSizeConstraintCallbackData { - void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraint() + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() ImVec2 Pos; // Read-only. Window position, for reference. ImVec2 CurrentSize; // Read-only. Current window size. ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d71343b3..a38e836f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1807,12 +1807,12 @@ static void ShowExampleAppConstrainedResize(bool* p_open) }; static int type = 0; - if (type == 0) ImGui::SetNextWindowSizeConstraint(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only - if (type == 1) ImGui::SetNextWindowSizeConstraint(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only - if (type == 2) ImGui::SetNextWindowSizeConstraint(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 - if (type == 3) ImGui::SetNextWindowSizeConstraint(ImVec2(300, 0), ImVec2(400, FLT_MAX)); // Width 300-400 - if (type == 4) ImGui::SetNextWindowSizeConstraint(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square - if (type == 5) ImGui::SetNextWindowSizeConstraint(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step + if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only + if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only + if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(300, 0), ImVec2(400, FLT_MAX)); // Width 300-400 + if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step if (ImGui::Begin("Example: Constrained Resize", p_open)) { From b5521a81d4c6a144a004f67320d9553099019340 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 14:18:46 +0200 Subject: [PATCH 201/400] Demo: fixed multi-selection tree nodes demo to not replace selection when clicking on single-item that's already part of selection (#581) --- imgui_demo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a38e836f..6fb75a9c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -275,9 +275,9 @@ void ImGui::ShowTestWindow(bool* p_open) { // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame. if (ImGui::GetIO().KeyCtrl) - selection_mask ^= (1 << node_clicked); // CTRL+click to toggle - else - selection_mask = (1 << node_clicked); // Click to single-select + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else if (!(selection_mask & (1 << node_clicked))) // If there is already a selection don't replace we clicked node is part of it + selection_mask = (1 << node_clicked); // Click to single-select } ImGui::TreePop(); } From 2acb61e3a1c7e5585a2532ad03178eaf30de818f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 16:52:59 +0200 Subject: [PATCH 202/400] Comments --- imgui.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index bc5fd2b6..3a0426b8 100644 --- a/imgui.h +++ b/imgui.h @@ -195,10 +195,10 @@ namespace ImGui IMGUI_API void Separator(); // horizontal line IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally IMGUI_API void NewLine(); // undo a SameLine() - IMGUI_API void Spacing(); // add spacing + IMGUI_API void Spacing(); // add vertical spacing IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size - IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels - IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) + IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing + IMGUI_API void Unindent(); // move content position back to the left by style.IndentSpacing IMGUI_API void BeginGroup(); // lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) IMGUI_API void EndGroup(); IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position @@ -208,7 +208,7 @@ namespace ImGui IMGUI_API void SetCursorPosX(float x); // " IMGUI_API void SetCursorPosY(float y); // " IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API) IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets IMGUI_API float GetTextLineHeight(); // height of font == GetWindowFontSize() @@ -216,7 +216,7 @@ namespace ImGui IMGUI_API float GetItemsLineHeightWithSpacing(); // distance (in pixels) between 2 consecutive lines of standard height widgets == GetWindowFontSize() + GetStyle().FramePadding.y*2 + GetStyle().ItemSpacing.y // Columns - // You can also use SameLine(pos_x) for simplified columning. The columns API is still work-in-progress. + // You can also use SameLine(pos_x) for simplified columning. The columns API is still work-in-progress and rather lacking. IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); // setup number of columns. use an identifier to distinguish multiple column sets. close with Columns(1). IMGUI_API void NextColumn(); // next column IMGUI_API int GetColumnIndex(); // get current column index @@ -252,7 +252,7 @@ namespace ImGui IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance you by the same distance as an empty TreeNode() call. IMGUI_API void BulletText(const char* fmt, ...) IM_PRINTFARGS(1); IMGUI_API void BulletTextV(const char* fmt, va_list args); - IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); + 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) IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); 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)); @@ -458,7 +458,7 @@ namespace ImGui // Obsolete (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - static inline bool CollapsingHeader(const char* label, const char* str_id, bool display_frame = true, bool default_open = false) { (void)str_id; (void)display_frame; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ + static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpen(open, 0); } // OBSOLETE 1.34+ @@ -659,6 +659,7 @@ enum ImGuiAlign_ }; // Enumeration for ColorEditMode() +// FIXME-OBSOLETE: Will be replaced by future color/picker api enum ImGuiColorEditMode_ { ImGuiColorEditMode_UserSelect = -2, From 806a1461989bdcc87162cb99a764845689b81911 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 17:12:13 +0200 Subject: [PATCH 203/400] TreeNodeEx(): ImGuiTreeNodeFlags_AlwaysOpen->ImGuiTreeNodeFlags_Leaf, + added ImGuiTreeNodeFlags_Bullet (#324, #581) --- imgui.cpp | 8 ++++---- imgui.h | 9 +++++---- imgui_demo.cpp | 39 ++++++++++++++++++++++++++------------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d677f2a6..1ec4cd2d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5776,7 +5776,7 @@ void ImGui::LogButtons() bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) { - if (flags & ImGuiTreeNodeFlags_AlwaysOpen) + if (flags & ImGuiTreeNodeFlags_Leaf) return true; // We only write to the tree storage if the user clicks (or explicitely use SetNextTreeNode*** functions) @@ -5871,7 +5871,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0); bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); - if (pressed && !(flags & ImGuiTreeNodeFlags_AlwaysOpen)) + if (pressed && !(flags & ImGuiTreeNodeFlags_Leaf)) { bool toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)); if (flags & ImGuiTreeNodeFlags_OpenOnArrow) @@ -5915,9 +5915,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (hovered || (flags & ImGuiTreeNodeFlags_Selected)) RenderFrame(bb.Min, bb.Max, col, false); - if (flags & ImGuiTreeNodeFlags_AlwaysOpen) + if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); - else + else if (!(flags & ImGuiTreeNodeFlags_Leaf)) RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open, 0.70f, false); if (g.LogEnabled) LogRenderedText(text_pos, ">"); diff --git a/imgui.h b/imgui.h index 3a0426b8..15af60fd 100644 --- a/imgui.h +++ b/imgui.h @@ -541,10 +541,11 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. - ImGuiTreeNodeFlags_AlwaysOpen = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). - //ImGuiTreeNodeFlags_UnindentArrow = 1 << 9, // FIXME: TODO: Unindent tree so that Label is aligned to current X position - //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 10, // FIXME: TODO: Extend hit box horizontally even if not framed - //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 11, // FIXME: TODO: Automatically scroll on TreePop() if node got just open and contents is not visible + ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow + //ImGuiTreeNodeFlags_UnindentArrow = 1 << 10, // FIXME: TODO: Unindent tree so that Label is aligned to current X position + //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Automatically scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6fb75a9c..c78f6965 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -253,22 +253,34 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("With selectable nodes")) { - ShowHelpMarker("Click to select, CTRL+Click to toggle, click on arrows to open"); - static int selection_mask = 0x02; // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. - int node_clicked = -1; + ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents. + static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. + int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. for (int i = 0; i < 6; i++) { + // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - if (i >= 3) - node_flags |= ImGuiTreeNodeFlags_AlwaysOpen; - bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable %s %d", (i >= 3) ? "Leaf" : "Node", i); - if (ImGui::IsItemClicked()) - node_clicked = i; - if (node_open) + if (i < 3) { - ImGui::Text("Selectable Blah blah"); - ImGui::Text("Blah blah"); - ImGui::TreePop(); + // Node + bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; + if (node_open) + { + ImGui::Text("Blah blah\nBlah Blah"); + ImGui::TreePop(); + } + } + else + { + // Leaf: Here we use the ImGuiTreeNodeFlags_Leaf functionality + ImGuiTreeNodeFlags_NoTreePushOnOpen to avoid testing return value and doing a TreePop + // The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or a simple Text() element offset by GetTreeNodeToLabelSpacing() + node_flags |= ImGuiTreeNodeFlags_Leaf|ImGuiTreeNodeFlags_NoTreePushOnOpen; + ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; } } if (node_clicked != -1) @@ -276,9 +288,10 @@ void ImGui::ShowTestWindow(bool* p_open) // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame. if (ImGui::GetIO().KeyCtrl) selection_mask ^= (1 << node_clicked); // CTRL+click to toggle - else if (!(selection_mask & (1 << node_clicked))) // If there is already a selection don't replace we clicked node is part of it + else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection selection_mask = (1 << node_clicked); // Click to single-select } + ImGui::PopStyleVar(); ImGui::TreePop(); } ImGui::TreePop(); From 793f5f8cdba94af35748f0b69a25716aae8346ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 17:54:40 +0200 Subject: [PATCH 204/400] Comments --- imgui.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index 15af60fd..24da799f 100644 --- a/imgui.h +++ b/imgui.h @@ -249,8 +249,8 @@ namespace ImGui IMGUI_API 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, recommended for long chunks of text IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_PRINTFARGS(2); // display text+label aligned the same way as value+label widgets IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args); - IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance you by the same distance as an empty TreeNode() call. - IMGUI_API void BulletText(const char* fmt, ...) IM_PRINTFARGS(1); + IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses + IMGUI_API void BulletText(const char* fmt, ...) IM_PRINTFARGS(1); // shortcut for Bullet()+Text() IMGUI_API void BulletTextV(const char* fmt, va_list args); 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) @@ -267,7 +267,7 @@ namespace ImGui IMGUI_API bool ColorButton(const ImVec4& col, bool small_height = false, bool outline_border = true); IMGUI_API bool ColorEdit3(const char* label, float col[3]); // Hint: 'float col[3]' function argument is same as 'float* col'. You can pass address of first element out of a contiguous set, e.g. &myvector.x IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true); // " - IMGUI_API void ColorEditMode(ImGuiColorEditMode mode); // FIXME-OBSOLETE: This is inconsistent with most of the API and should be obsoleted. + IMGUI_API void ColorEditMode(ImGuiColorEditMode mode); // FIXME-OBSOLETE: This is inconsistent with most of the API and will be obsoleted/replaced. IMGUI_API 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), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), int stride = sizeof(float)); @@ -323,9 +323,9 @@ namespace ImGui IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_PRINTFARGS(3); IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args); IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args); - IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layout purpose + IMGUI_API void TreePush(const char* str_id = NULL); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call Push/Pop yourself for layout purpose IMGUI_API void TreePush(const void* ptr_id = NULL); // " - IMGUI_API void TreePop(); + IMGUI_API void TreePop(); // ~ Unindent()+PopId() IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond = 0); // set next TreeNode/CollapsingHeader open state. IMGUI_API float GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags = 0); // return horizontal distance between cursor and text label due to collapsing node. == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. user doesn't have to call TreePop(). @@ -530,7 +530,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() }; -// Flags for ImGui::TreeNode*(), ImGui::CollapsingHeader*() +// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() enum ImGuiTreeNodeFlags_ { ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected @@ -545,7 +545,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow //ImGuiTreeNodeFlags_UnindentArrow = 1 << 10, // FIXME: TODO: Unindent tree so that Label is aligned to current X position //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed - //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Automatically scroll on TreePop() if node got just open and contents is not visible + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; From a0a48f6e59772d709f1768a6aeb67023df234179 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 18:15:54 +0200 Subject: [PATCH 205/400] Added TreeAdvanceToLabelPos() (#581) --- imgui.cpp | 17 +++++++++-------- imgui.h | 3 ++- imgui_demo.cpp | 6 ++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1ec4cd2d..fec7c37b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6043,19 +6043,20 @@ bool ImGui::TreeNode(const char* label) ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - return TreeNodeBehavior(window->GetID(label), 0, label, NULL); } -float ImGui::GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags) +void ImGui::TreeAdvanceToLabelPos() { ImGuiContext& g = *GImGui; - float off_from_start; - if (flags & ImGuiTreeNodeFlags_Framed) - off_from_start = g.FontSize + (g.Style.FramePadding.x * 3.0f) - ((float)(int)(g.CurrentWindow->WindowPadding.x*0.5f) - 1); - else - off_from_start = g.FontSize + (g.Style.FramePadding.x * 2.0f); - return off_from_start; + g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing(); +} + +// Horizontal distance preceeding label when using TreeNode() or Bullet() +float ImGui::GetTreeNodeToLabelSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + (g.Style.FramePadding.x * 2.0f); } void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond) diff --git a/imgui.h b/imgui.h index 24da799f..c455cb71 100644 --- a/imgui.h +++ b/imgui.h @@ -326,8 +326,9 @@ namespace ImGui IMGUI_API void TreePush(const char* str_id = NULL); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call Push/Pop yourself for layout purpose 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() + IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceeding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond = 0); // set next TreeNode/CollapsingHeader open state. - IMGUI_API float GetTreeNodeToLabelSpacing(ImGuiTreeNodeFlags flags = 0); // return horizontal distance between cursor and text label due to collapsing node. == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c78f6965..3d92424d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -275,10 +275,8 @@ void ImGui::ShowTestWindow(bool* p_open) } else { - // Leaf: Here we use the ImGuiTreeNodeFlags_Leaf functionality + ImGuiTreeNodeFlags_NoTreePushOnOpen to avoid testing return value and doing a TreePop - // The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or a simple Text() element offset by GetTreeNodeToLabelSpacing() - node_flags |= ImGuiTreeNodeFlags_Leaf|ImGuiTreeNodeFlags_NoTreePushOnOpen; - ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + // 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(). + ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Selectable Leaf %d", i); if (ImGui::IsItemClicked()) node_clicked = i; } From 61c294bb52c234c3b777762b70f56551198797e6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 18:40:00 +0200 Subject: [PATCH 206/400] Added optional Indent() Unindent() width (#324, #581) --- imgui.cpp | 14 +++++++------- imgui.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fec7c37b..a31498fa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -546,12 +546,12 @@ - drag float: up/down axis - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) - tree node / optimization: avoid formatting when clipped. - - tree node: clarify spacing, perhaps provide API to query exact spacing. provide API to draw the primitive. same with Bullet(). - tree node: tree-node/header right-most side doesn't take account of horizontal scrolling. - - tree node: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings + - tree node: add treenode/treepush int variants? not there because (void*) cast from int warns on some platforms/settings? - tree node: try to apply scrolling at time of TreePop() if node was just opened and end of node is past scrolling limits? - tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer) - - textwrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (git issue #249) + - tree node: tweak color scheme to distinguish headers from selected tree node (#581) + - textwrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (#249) - settings: write more decent code to allow saving/loading new fields - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file - style: add window shadows. @@ -9375,19 +9375,19 @@ void ImGui::Columns(int columns_count, const char* id, bool border) } } -void ImGui::Indent() +void ImGui::Indent(float indent_w) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - window->DC.IndentX += g.Style.IndentSpacing; + window->DC.IndentX += (indent_w > 0.0f) ? indent_w : g.Style.IndentSpacing; window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX; } -void ImGui::Unindent() +void ImGui::Unindent(float indent_w) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - window->DC.IndentX -= g.Style.IndentSpacing; + window->DC.IndentX -= (indent_w > 0.0f) ? indent_w : g.Style.IndentSpacing; window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX; } diff --git a/imgui.h b/imgui.h index c455cb71..251cef08 100644 --- a/imgui.h +++ b/imgui.h @@ -197,8 +197,8 @@ namespace ImGui IMGUI_API void NewLine(); // undo a SameLine() IMGUI_API void Spacing(); // add vertical spacing IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size - IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing - IMGUI_API void Unindent(); // move content position back to the left by style.IndentSpacing + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if >0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if >0 IMGUI_API void BeginGroup(); // lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) IMGUI_API void EndGroup(); IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position From 1483a69c111552b0fbd653096105a616d9980bbb Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 May 2016 19:30:01 +0200 Subject: [PATCH 207/400] Demo: Tree: showing how to align tree node label with current x position (#324, #581) --- imgui.cpp | 2 +- imgui.h | 5 ++--- imgui_demo.cpp | 14 +++++++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a31498fa..703fb7cf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5847,7 +5847,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1; } - const float text_offset_x = g.FontSize + (display_frame ? padding.x*3 : padding.x*2); // Collapser arrow width + Spacing + const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser ItemSize(ImVec2(text_width, frame_height), text_base_offset_y); diff --git a/imgui.h b/imgui.h index 251cef08..80493422 100644 --- a/imgui.h +++ b/imgui.h @@ -544,9 +544,8 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow - //ImGuiTreeNodeFlags_UnindentArrow = 1 << 10, // FIXME: TODO: Unindent tree so that Label is aligned to current X position - //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed - //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible + //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 10, // FIXME: TODO: Extend hit box horizontally even if not framed + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 11, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3d92424d..d98b7fff 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -251,16 +251,22 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::TreePop(); } - if (ImGui::TreeNode("With selectable nodes")) + if (ImGui::TreeNode("Advanced, with Selectable nodes")) { ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); - ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents. + static bool align_label_with_current_x_position = false; + ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position); + ImGui::Text("Hello!"); + if (align_label_with_current_x_position) + ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); + static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents. for (int i = 0; i < 6; i++) { // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. - ImGuiTreeNodeFlags node_flags = ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; + ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0); if (i < 3) { // Node @@ -290,6 +296,8 @@ void ImGui::ShowTestWindow(bool* p_open) selection_mask = (1 << node_clicked); // Click to single-select } ImGui::PopStyleVar(); + if (align_label_with_current_x_position) + ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); ImGui::TreePop(); } ImGui::TreePop(); From d5a12866fe6d9b0dbe6e7323b11af27b6a84e1f9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 14:00:35 +0200 Subject: [PATCH 208/400] Comments (#676, #655) --- imgui.cpp | 1 + imgui.h | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 703fb7cf..7f89e9bd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -162,6 +162,7 @@ float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } + If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). diff --git a/imgui.h b/imgui.h index 80493422..c894860e 100644 --- a/imgui.h +++ b/imgui.h @@ -145,10 +145,10 @@ namespace ImGui IMGUI_API void SetNextWindowContentWidth(float width); // set next window content width (enforce the range of horizontal scrollbar). call before Begin() IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. call before Begin() IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin() - IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing - IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set current window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing - IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set current window collapsed state - IMGUI_API void SetWindowFocus(); // set current window to be focused / front-most + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). + IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus(). IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position. IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state From 45dacbf084e897c317d034275fbd070ed71c0709 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 17:50:23 +0200 Subject: [PATCH 209/400] Fixed GetWindowContentRegionMax() being off by ScrollSize amount when SizeExplicit is set + caching ContentsRegionRect. Relates to horizontal scrollbar, explicit contents size --- imgui.cpp | 19 +++++++++++-------- imgui_internal.h | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7f89e9bd..3c310dd6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4201,6 +4201,12 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us } } + // Update ContentsRegionMax. All the variable it depends on are set above in this function. + window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x; + window->ContentsRegionRect.Min.x = -window->Scroll.y + window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y; + window->ContentsRegionRect.Max.x = (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x) - window->Scroll.x - window->WindowPadding.x; + window->ContentsRegionRect.Max.y = (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y) - window->Scroll.y - window->WindowPadding.y; + // Setup drawing context window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; window->DC.ColumnsOffsetX = 0.0f; @@ -4970,12 +4976,10 @@ void ImGui::SetNextWindowFocus() } // In window space (not screen space!) -// FIXME-OPT: Could cache and maintain it (pretty much only change on columns change) ImVec2 ImGui::GetContentRegionMax() { ImGuiWindow* window = GetCurrentWindowRead(); - ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x, window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y); - ImVec2 mx = content_region_size - window->Scroll - window->WindowPadding; + ImVec2 mx = window->ContentsRegionRect.Max; if (window->DC.ColumnsCount != 1) mx.x = ImGui::GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x; return mx; @@ -4996,20 +5000,19 @@ float ImGui::GetContentRegionAvailWidth() ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GetCurrentWindowRead(); - return ImVec2(-window->Scroll.x, -window->Scroll.y + window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding; + return window->ContentsRegionRect.Min; } ImVec2 ImGui::GetWindowContentRegionMax() { ImGuiWindow* window = GetCurrentWindowRead(); - ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y); - ImVec2 m = content_region_size - window->Scroll - window->WindowPadding - window->ScrollbarSizes; - return m; + return window->ContentsRegionRect.Max; } float ImGui::GetWindowContentRegionWidth() { - return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ContentsRegionRect.Max.x - window->ContentsRegionRect.Min.x; } float ImGui::GetTextLineHeight() diff --git a/imgui_internal.h b/imgui_internal.h index c787dbd1..c67eab92 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -607,6 +607,7 @@ struct IMGUI_API ImGuiWindow ImVec2 SizeFull; // Size when non collapsed ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize() + ImRect ContentsRegionRect; // Maximum visible content position in window coordinates. ~~ (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis ImVec2 WindowPadding; // Window padding at the time of begin. We need to lock it, in particular manipulation of the ShowBorder would have an effect ImGuiID MoveID; // == window->GetID("#MOVE") ImVec2 Scroll; From dff078365fb8473ffdd6cc060386fdefa30d1e5c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 18:08:51 +0200 Subject: [PATCH 210/400] Fix selectable/tree node not reaching right-side of contents size when horizontal scrolling is active and no explicit size is known --- imgui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3c310dd6..3f73781c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4203,9 +4203,9 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Update ContentsRegionMax. All the variable it depends on are set above in this function. window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x; - window->ContentsRegionRect.Min.x = -window->Scroll.y + window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y; - window->ContentsRegionRect.Max.x = (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x) - window->Scroll.x - window->WindowPadding.x; - window->ContentsRegionRect.Max.y = (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.y) - window->Scroll.y - window->WindowPadding.y; + window->ContentsRegionRect.Min.x = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); + window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : ImMax(window->SizeContents.x, window->Size.x - window->ScrollbarSizes.x)); + window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : ImMax(window->SizeContents.y, window->Size.y - window->ScrollbarSizes.y)); // Setup drawing context window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; From 784e1ef053baa87410f1e397d379d3494d9e9181 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 18:12:25 +0200 Subject: [PATCH 211/400] CollapsingHeader() with close button adapt to horizontal scrolling (#600) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 3f73781c..0e9ee827 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5958,7 +5958,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. ImGuiContext& g = *GImGui; float button_sz = g.FontSize * 0.5f; - if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(window->DC.LastItemRect.Max.x - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz)) + if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz)) *p_open = false; } From dcef7dedce84b780d7f9c42b4effec6153210197 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 18:24:02 +0200 Subject: [PATCH 212/400] Comments (#590) --- imgui.cpp | 2 ++ imgui.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 0e9ee827..2567d604 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5933,6 +5933,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return is_open; } +// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). +// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui.h b/imgui.h index c894860e..a3db5b06 100644 --- a/imgui.h +++ b/imgui.h @@ -329,7 +329,7 @@ namespace ImGui IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing() IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceeding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond = 0); // set next TreeNode/CollapsingHeader open state. - IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. user doesn't have to call TreePop(). + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header // Widgets: Selectable / Lists From 9886c1b43d79b60f5502e0293f099ecdfe501f6c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 18:37:26 +0200 Subject: [PATCH 213/400] Undo modification of ContentsRegionRect.Max, too many side-effects (undo dff078365fb8473ffdd6cc060386fdefa30d1e5c) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2567d604..e92e807b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4204,8 +4204,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Update ContentsRegionMax. All the variable it depends on are set above in this function. window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x; window->ContentsRegionRect.Min.x = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); - window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : ImMax(window->SizeContents.x, window->Size.x - window->ScrollbarSizes.x)); - window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : ImMax(window->SizeContents.y, window->Size.y - window->ScrollbarSizes.y)); + window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x)); + window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y)); // Setup drawing context window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; From 0fb51b6b4bca115074b7c4bb8cf5815081d53812 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 18:58:41 +0200 Subject: [PATCH 214/400] Removed various superflous ImGui:: prefixes in internal code --- imgui.cpp | 554 +++++++++++++++++++++++++++--------------------------- 1 file changed, 275 insertions(+), 279 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e92e807b..90e6a24d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1927,7 +1927,7 @@ ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y) ImGuiContext& g = *GImGui; ImVec2 content_max; if (size.x < 0.0f || size.y < 0.0f) - content_max = g.CurrentWindow->Pos + ImGui::GetContentRegionMax(); + content_max = g.CurrentWindow->Pos + GetContentRegionMax(); if (size.x <= 0.0f) size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x; if (size.y <= 0.0f) @@ -1942,7 +1942,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) ImGuiWindow* window = GetCurrentWindowRead(); if (wrap_pos_x == 0.0f) - wrap_pos_x = ImGui::GetContentRegionMax().x + window->Pos.x; + wrap_pos_x = GetContentRegionMax().x + window->Pos.x; else if (wrap_pos_x > 0.0f) wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space @@ -2834,7 +2834,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons // Perform CPU side clipping for single clipped element to avoid using scissor state ImVec2 pos = pos_min; - const ImVec2 text_size = text_size_if_known ? *text_size_if_known : ImGui::CalcTextSize(text, text_display_end, false, 0.0f); + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); if (!clip_max) clip_max = &pos_max; bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); @@ -3504,26 +3504,26 @@ void ImGui::EndPopup() // driven by click position. bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button) { - if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(mouse_button)) - ImGui::OpenPopupEx(str_id, false); - return ImGui::BeginPopup(str_id); + if (IsItemHovered() && IsMouseClicked(mouse_button)) + OpenPopupEx(str_id, false); + return BeginPopup(str_id); } bool ImGui::BeginPopupContextWindow(bool also_over_items, const char* str_id, int mouse_button) { if (!str_id) str_id = "window_context_menu"; - if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(mouse_button)) - if (also_over_items || !ImGui::IsAnyItemHovered()) - ImGui::OpenPopupEx(str_id, true); - return ImGui::BeginPopup(str_id); + if (IsMouseHoveringWindow() && IsMouseClicked(mouse_button)) + if (also_over_items || !IsAnyItemHovered()) + OpenPopupEx(str_id, true); + return BeginPopup(str_id); } bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) { if (!str_id) str_id = "void_context_menu"; - if (!ImGui::IsMouseHoveringAnyWindow() && ImGui::IsMouseClicked(mouse_button)) - ImGui::OpenPopupEx(str_id, true); - return ImGui::BeginPopup(str_id); + if (!IsMouseHoveringAnyWindow() && IsMouseClicked(mouse_button)) + OpenPopupEx(str_id, true); + return BeginPopup(str_id); } bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) @@ -3531,7 +3531,7 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindow* window = GetCurrentWindow(); ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; - const ImVec2 content_avail = ImGui::GetContentRegionAvail(); + const ImVec2 content_avail = GetContentRegionAvail(); ImVec2 size = ImFloor(size_arg); if (size.x <= 0.0f) { @@ -3580,7 +3580,7 @@ void ImGui::EndChild() else { // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting. - ImVec2 sz = ImGui::GetWindowSize(); + ImVec2 sz = GetWindowSize(); if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f sz.x = ImMax(4.0f, sz.x); if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitY) @@ -4330,12 +4330,12 @@ void ImGui::End() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImGui::Columns(1, "#CloseColumns"); + Columns(1, "#CloseColumns"); PopClipRect(); // inner window clip rectangle // Stop logging if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging - ImGui::LogFinish(); + LogFinish(); // Pop // NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin(). @@ -4516,7 +4516,7 @@ float ImGui::CalcItemWidth() if (w < 0.0f) { // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well. - float width_to_right_edge = ImGui::GetContentRegionAvail().x; + float width_to_right_edge = GetContentRegionAvail().x; w = ImMax(1.0f, width_to_right_edge + w); } w = (float)(int)w; @@ -4981,7 +4981,7 @@ ImVec2 ImGui::GetContentRegionMax() ImGuiWindow* window = GetCurrentWindowRead(); ImVec2 mx = window->ContentsRegionRect.Max; if (window->DC.ColumnsCount != 1) - mx.x = ImGui::GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x; + mx.x = GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x; return mx; } @@ -5173,7 +5173,7 @@ void ImGui::SetScrollHere(float center_y_ratio) { ImGuiWindow* window = GetCurrentWindow(); float target_y = window->DC.CursorPosPrevLine.y + (window->DC.PrevLineHeight * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line. - ImGui::SetScrollFromPosY(target_y - window->Pos.y, center_y_ratio); + SetScrollFromPosY(target_y - window->Pos.y, center_y_ratio); } void ImGui::SetKeyboardFocusHere(int offset) @@ -5216,9 +5216,9 @@ void ImGui::Text(const char* fmt, ...) void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) { - ImGui::PushStyleColor(ImGuiCol_Text, col); + PushStyleColor(ImGuiCol_Text, col); TextV(fmt, args); - ImGui::PopStyleColor(); + PopStyleColor(); } void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) @@ -5231,9 +5231,9 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) void ImGui::TextDisabledV(const char* fmt, va_list args) { - ImGui::PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); + PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); TextV(fmt, args); - ImGui::PopStyleColor(); + PopStyleColor(); } void ImGui::TextDisabled(const char* fmt, ...) @@ -5246,9 +5246,9 @@ void ImGui::TextDisabled(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - ImGui::PushTextWrapPos(0.0f); + PushTextWrapPos(0.0f); TextV(fmt, args); - ImGui::PopTextWrapPos(); + PopTextWrapPos(); } void ImGui::TextWrapped(const char* fmt, ...) @@ -5280,7 +5280,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. const char* line = text; - const float line_height = ImGui::GetTextLineHeight(); + const float line_height = GetTextLineHeight(); const ImVec2 text_pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrentLineTextBaseOffset); const ImRect clip_rect = window->ClipRect; ImVec2 text_size(0,0); @@ -5311,7 +5311,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // Lines to render if (line < text_end) { - ImRect line_rect(pos, pos + ImVec2(ImGui::GetWindowWidth(), line_height)); + ImRect line_rect(pos, pos + ImVec2(GetWindowWidth(), line_height)); while (line < text_end) { const char* line_end = strchr(line, '\n'); @@ -5377,7 +5377,7 @@ void ImGui::AlignFirstTextHeightToWidgets() // Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height. ImGuiContext& g = *GImGui; ItemSize(ImVec2(0, g.FontSize + g.Style.FramePadding.y*2), g.Style.FramePadding.y); - ImGui::SameLine(0, 0); + SameLine(0, 0); } // Add a label+text combo aligned to other label+value widgets @@ -5475,7 +5475,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. - if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && ImGui::IsMouseClicked(0, true)) + if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true)) pressed = true; } } @@ -5538,7 +5538,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) - // ImGui::CloseCurrentPopup(); + // CloseCurrentPopup(); return pressed; } @@ -5583,23 +5583,23 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) // Upper-right button to close a window. bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) { - ImGuiWindow* window = ImGui::GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindow(); const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius)); bool hovered, held; - bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); + bool pressed = ButtonBehavior(bb, id, &hovered, &held); // Render - const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); const ImVec2 center = bb.GetCenter(); window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), col, 12); const float cross_extent = (radius * 0.7071f) - 1.0f; if (hovered) { - window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), ImGui::GetColorU32(ImGuiCol_Text)); - window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), ImGui::GetColorU32(ImGuiCol_Text)); + window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), GetColorU32(ImGuiCol_Text)); + window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), GetColorU32(ImGuiCol_Text)); } return pressed; @@ -5644,9 +5644,9 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I // Default to using texture ID as ID. User can still push string/integer prefixes. // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV. - ImGui::PushID((void *)user_texture_id); + PushID((void *)user_texture_id); const ImGuiID id = window->GetID("#image"); - ImGui::PopID(); + PopID(); const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2); @@ -5731,7 +5731,7 @@ void ImGui::LogFinish() if (!g.LogEnabled) return; - ImGui::LogText(IM_NEWLINE); + LogText(IM_NEWLINE); g.LogEnabled = false; if (g.LogFile != NULL) { @@ -5754,20 +5754,16 @@ void ImGui::LogButtons() { ImGuiContext& g = *GImGui; - ImGui::PushID("LogButtons"); - const bool log_to_tty = ImGui::Button("Log To TTY"); - ImGui::SameLine(); - const bool log_to_file = ImGui::Button("Log To File"); - ImGui::SameLine(); - const bool log_to_clipboard = ImGui::Button("Log To Clipboard"); - ImGui::SameLine(); - - ImGui::PushItemWidth(80.0f); - ImGui::PushAllowKeyboardFocus(false); - ImGui::SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL); - ImGui::PopAllowKeyboardFocus(); - ImGui::PopItemWidth(); - ImGui::PopID(); + PushID("LogButtons"); + const bool log_to_tty = Button("Log To TTY"); SameLine(); + const bool log_to_file = Button("Log To File"); SameLine(); + const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); + PushItemWidth(80.0f); + PushAllowKeyboardFocus(false); + SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL); + PopAllowKeyboardFocus(); + PopItemWidth(); + PopID(); // Start logging at the end of the function so that the buttons don't appear in the log if (log_to_tty) @@ -6131,7 +6127,7 @@ void ImGui::Bullet() ItemSize(bb); if (!ItemAdd(bb, NULL)) { - ImGui::SameLine(0, style.FramePadding.x*2); + SameLine(0, style.FramePadding.x*2); return; } @@ -6594,7 +6590,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max) { float v_deg = (*v_rad) * 360.0f / (2*IM_PI); - bool value_changed = ImGui::SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f); + bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f); *v_rad = v_deg * (2*IM_PI) / 360.0f; return value_changed; } @@ -6604,7 +6600,7 @@ bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const cha if (!display_format) display_format = "%.0f"; float v_f = (float)*v; - bool value_changed = ImGui::SliderFloat(label, &v_f, (float)v_min, (float)v_max, display_format, 1.0f); + bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, display_format, 1.0f); *v = (int)v_f; return value_changed; } @@ -6614,7 +6610,7 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, if (!display_format) display_format = "%.0f"; float v_f = (float)*v; - bool value_changed = ImGui::VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f); + bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f); *v = (int)v_f; return value_changed; } @@ -6628,21 +6624,21 @@ bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_mi ImGuiContext& g = *GImGui; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); PushMultiItemsWidths(components); for (int i = 0; i < components; i++) { - ImGui::PushID(i); - value_changed |= ImGui::SliderFloat("##v", &v[i], v_min, v_max, display_format, power); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); - ImGui::PopItemWidth(); + PushID(i); + value_changed |= SliderFloat("##v", &v[i], v_min, v_max, display_format, power); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); } - ImGui::PopID(); + PopID(); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); return value_changed; } @@ -6670,21 +6666,21 @@ bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int ImGuiContext& g = *GImGui; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); PushMultiItemsWidths(components); for (int i = 0; i < components; i++) { - ImGui::PushID(i); - value_changed |= ImGui::SliderInt("##v", &v[i], v_min, v_max, display_format); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); - ImGui::PopItemWidth(); + PushID(i); + value_changed |= SliderInt("##v", &v[i], v_min, v_max, display_format); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); } - ImGui::PopID(); + PopID(); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); return value_changed; } @@ -6728,7 +6724,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s } float v_cur = g.DragCurrentValue; - const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f); + const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f); if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f) { float speed = v_speed; @@ -6850,21 +6846,21 @@ bool ImGui::DragFloatN(const char* label, float* v, int components, float v_spee ImGuiContext& g = *GImGui; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); PushMultiItemsWidths(components); for (int i = 0; i < components; i++) { - ImGui::PushID(i); - value_changed |= ImGui::DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); - ImGui::PopItemWidth(); + PushID(i); + value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); } - ImGui::PopID(); + PopID(); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); return value_changed; } @@ -6891,20 +6887,20 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu return false; ImGuiContext& g = *GImGui; - ImGui::PushID(label); - ImGui::BeginGroup(); + PushID(label); + BeginGroup(); PushMultiItemsWidths(2); - bool value_changed = ImGui::DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format, power); - ImGui::PopItemWidth(); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= ImGui::DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, display_format_max ? display_format_max : display_format, power); - ImGui::PopItemWidth(); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); + bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format, power); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, display_format_max ? display_format_max : display_format, power); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); - ImGui::PopID(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); return value_changed; } @@ -6915,7 +6911,7 @@ bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_m if (!display_format) display_format = "%.0f"; float v_f = (float)*v; - bool value_changed = ImGui::DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format); + bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format); *v = (int)v_f; return value_changed; } @@ -6928,21 +6924,21 @@ bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, i ImGuiContext& g = *GImGui; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); PushMultiItemsWidths(components); for (int i = 0; i < components; i++) { - ImGui::PushID(i); - value_changed |= ImGui::DragInt("##v", &v[i], v_speed, v_min, v_max, display_format); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); - ImGui::PopItemWidth(); + PushID(i); + value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, display_format); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); } - ImGui::PopID(); + PopID(); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); return value_changed; } @@ -6969,20 +6965,20 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ return false; ImGuiContext& g = *GImGui; - ImGui::PushID(label); - ImGui::BeginGroup(); + PushID(label); + BeginGroup(); PushMultiItemsWidths(2); - bool value_changed = ImGui::DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format); - ImGui::PopItemWidth(); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - value_changed |= ImGui::DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, display_format_max ? display_format_max : display_format); - ImGui::PopItemWidth(); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); + bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, display_format_max ? display_format_max : display_format); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); - ImGui::PopID(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); return value_changed; } @@ -7042,9 +7038,9 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge const float v0 = values_getter(data, (v_idx + values_offset) % values_count); const float v1 = values_getter(data, (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); + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); else if (plot_type == ImGuiPlotType_Histogram) - ImGui::SetTooltip("%d: %8.4g", v_idx, v0); + SetTooltip("%d: %8.4g", v_idx, v0); v_hovered = v_idx; } @@ -7215,7 +7211,7 @@ bool ImGui::Checkbox(const char* label, bool* v) bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) { bool v = ((*flags & flags_value) == flags_value); - bool pressed = ImGui::Checkbox(label, &v); + bool pressed = Checkbox(label, &v); if (pressed) { if (v) @@ -7286,7 +7282,7 @@ bool ImGui::RadioButton(const char* label, bool active) bool ImGui::RadioButton(const char* label, int* v, int v_button) { - const bool pressed = ImGui::RadioButton(label, *v == v_button); + const bool pressed = RadioButton(label, *v == v_button); if (pressed) { *v = v_button; @@ -7567,18 +7563,18 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const ImVec2 label_size = CalcTextSize(label, NULL, true); - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? ImGui::GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); ImGuiWindow* draw_window = window; if (is_multiline) { - ImGui::BeginGroup(); - if (!ImGui::BeginChildFrame(id, frame_bb.GetSize())) + BeginGroup(); + if (!BeginChildFrame(id, frame_bb.GetSize())) { - ImGui::EndChildFrame(); - ImGui::EndGroup(); + EndChildFrame(); + EndGroup(); return false; } draw_window = GetCurrentWindow(); @@ -7605,7 +7601,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 password_font->FallbackGlyph = glyph; password_font->FallbackXAdvance = glyph->XAdvance; IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexXAdvance.empty() && password_font->IndexLookup.empty()); - ImGui::PushFont(password_font); + PushFont(password_font); } // NB: we are only allowed to access 'edit_state' if we are the active widget. @@ -8090,13 +8086,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (is_multiline) { - ImGui::Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line - ImGui::EndChildFrame(); - ImGui::EndGroup(); + Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line + EndChildFrame(); + EndGroup(); } if (is_password) - ImGui::PopFont(); + PopFont(); // Log as text if (g.LogEnabled && !is_password) @@ -8135,11 +8131,11 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data const ImGuiStyle& style = g.Style; const ImVec2 label_size = CalcTextSize(label, NULL, true); - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); const ImVec2 button_sz = ImVec2(g.FontSize, g.FontSize) + style.FramePadding*2.0f; if (step_ptr) - ImGui::PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_sz.x + style.ItemInnerSpacing.x)*2)); + PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_sz.x + style.ItemInnerSpacing.x)*2)); char buf[64]; DataTypeFormatString(data_type, data_ptr, scalar_format, buf, IM_ARRAYSIZE(buf)); @@ -8148,35 +8144,35 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal)) extra_flags |= ImGuiInputTextFlags_CharsDecimal; extra_flags |= ImGuiInputTextFlags_AutoSelectAll; - if (ImGui::InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) + if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format); // Step buttons if (step_ptr) { - ImGui::PopItemWidth(); - ImGui::SameLine(0, style.ItemInnerSpacing.x); + PopItemWidth(); + SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("-", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { DataTypeApplyOp(data_type, '-', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr); value_changed = true; } - ImGui::SameLine(0, style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("+", button_sz, ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { DataTypeApplyOp(data_type, '+', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr); value_changed = true; } } - ImGui::PopID(); + PopID(); if (label_size.x > 0) { - ImGui::SameLine(0, style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label); ItemSize(label_size, style.FramePadding.y); } - ImGui::EndGroup(); + EndGroup(); return value_changed; } @@ -8206,22 +8202,22 @@ bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal ImGuiContext& g = *GImGui; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); PushMultiItemsWidths(components); for (int i = 0; i < components; i++) { - ImGui::PushID(i); - value_changed |= ImGui::InputFloat("##v", &v[i], 0, 0, decimal_precision, extra_flags); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); - ImGui::PopItemWidth(); + PushID(i); + value_changed |= InputFloat("##v", &v[i], 0, 0, decimal_precision, extra_flags); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); } - ImGui::PopID(); + PopID(); window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); return value_changed; } @@ -8249,22 +8245,22 @@ bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextF ImGuiContext& g = *GImGui; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); PushMultiItemsWidths(components); for (int i = 0; i < components; i++) { - ImGui::PushID(i); - value_changed |= ImGui::InputInt("##v", &v[i], 0, 0, extra_flags); - ImGui::SameLine(0, g.Style.ItemInnerSpacing.x); - ImGui::PopID(); - ImGui::PopItemWidth(); + PushID(i); + value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags); + SameLine(0, g.Style.ItemInnerSpacing.x); + PopID(); + PopItemWidth(); } - ImGui::PopID(); + PopID(); window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); - ImGui::TextUnformatted(label, FindRenderedTextEnd(label)); - ImGui::EndGroup(); + TextUnformatted(label, FindRenderedTextEnd(label)); + EndGroup(); return value_changed; } @@ -8408,35 +8404,35 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi popup_y2 = frame_bb.Min.y; } ImRect popup_rect(ImVec2(frame_bb.Min.x, popup_y1), ImVec2(frame_bb.Max.x, popup_y2)); - ImGui::SetNextWindowPos(popup_rect.Min); - ImGui::SetNextWindowSize(popup_rect.GetSize()); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + SetNextWindowPos(popup_rect.Min); + SetNextWindowSize(popup_rect.GetSize()); + PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0); if (BeginPopupEx(label, flags)) { // Display items - ImGui::Spacing(); + Spacing(); for (int i = 0; i < items_count; i++) { - ImGui::PushID((void*)(intptr_t)i); + PushID((void*)(intptr_t)i); const bool item_selected = (i == *current_item); const char* item_text; if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*"; - if (ImGui::Selectable(item_text, item_selected)) + if (Selectable(item_text, item_selected)) { SetActiveID(0); value_changed = true; *current_item = i; } if (item_selected && popup_opened_now) - ImGui::SetScrollHere(); - ImGui::PopID(); + SetScrollHere(); + PopID(); } - ImGui::EndPopup(); + EndPopup(); } - ImGui::PopStyleVar(); + PopStyleVar(); } return value_changed; } @@ -8465,7 +8461,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Fill horizontal space. ImVec2 window_padding = window->WindowPadding; - float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? ImGui::GetWindowContentRegionMax().x : ImGui::GetContentRegionMax().x; + float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x; float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x); ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y); ImRect bb_with_spacing(pos, pos + size_draw); @@ -8508,22 +8504,22 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1) { PushColumnClipRect(); - bb_with_spacing.Max.x -= (ImGui::GetContentRegionMax().x - max_x); + bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x); } - if (flags & ImGuiSelectableFlags_Disabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size); - if (flags & ImGuiSelectableFlags_Disabled) ImGui::PopStyleColor(); + if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); // Automatically close popups if (pressed && !(flags & ImGuiSelectableFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) - ImGui::CloseCurrentPopup(); + CloseCurrentPopup(); return pressed; } bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) { - if (ImGui::Selectable(label, *p_selected, flags, size_arg)) + if (Selectable(label, *p_selected, flags, size_arg)) { *p_selected = !*p_selected; return true; @@ -8539,22 +8535,22 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) if (window->SkipItems) return false; - const ImGuiStyle& style = ImGui::GetStyle(); - const ImGuiID id = ImGui::GetID(label); + const ImGuiStyle& style = GetStyle(); + const ImGuiID id = GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); window->DC.LastItemRect = bb; - ImGui::BeginGroup(); + BeginGroup(); if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - ImGui::BeginChildFrame(id, frame_bb.GetSize()); + BeginChildFrame(id, frame_bb.GetSize()); return true; } @@ -8570,24 +8566,24 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). ImVec2 size; size.x = 0.0f; - size.y = ImGui::GetTextLineHeightWithSpacing() * height_in_items_f + ImGui::GetStyle().ItemSpacing.y; - return ImGui::ListBoxHeader(label, size); + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y; + return ListBoxHeader(label, size); } void ImGui::ListBoxFooter() { ImGuiWindow* parent_window = GetParentWindow(); const ImRect bb = parent_window->DC.LastItemRect; - const ImGuiStyle& style = ImGui::GetStyle(); + const ImGuiStyle& style = GetStyle(); - ImGui::EndChildFrame(); + EndChildFrame(); // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) // We call SameLine() to restore DC.CurrentLine* data - ImGui::SameLine(); + SameLine(); parent_window->DC.CursorPos = bb.Min; ItemSize(bb, style.FramePadding.y); - ImGui::EndGroup(); + EndGroup(); } bool ImGui::ListBox(const char* label, int* current_item, const char** items, int items_count, int height_items) @@ -8598,12 +8594,12 @@ bool ImGui::ListBox(const char* label, int* current_item, const char** items, in bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) { - if (!ImGui::ListBoxHeader(label, items_count, height_in_items)) + if (!ListBoxHeader(label, items_count, height_in_items)) return false; // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. bool value_changed = false; - ImGuiListClipper clipper(items_count, ImGui::GetTextLineHeightWithSpacing()); + ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { @@ -8612,15 +8608,15 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*"; - ImGui::PushID(i); - if (ImGui::Selectable(item_text, item_selected)) + PushID(i); + if (Selectable(item_text, item_selected)) { *current_item = i; value_changed = true; } - ImGui::PopID(); + PopID(); } - ImGui::ListBoxFooter(); + ListBoxFooter(); return value_changed; } @@ -8635,14 +8631,14 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f); float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame - float extra_w = ImMax(0.0f, ImGui::GetContentRegionAvail().x - w); + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); - bool pressed = ImGui::Selectable(label, false, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DrawFillAvailWidth | (enabled ? 0 : ImGuiSelectableFlags_Disabled), ImVec2(w, 0.0f)); + bool pressed = Selectable(label, false, ImGuiSelectableFlags_MenuItem | ImGuiSelectableFlags_DrawFillAvailWidth | (enabled ? 0 : ImGuiSelectableFlags_Disabled), ImVec2(w, 0.0f)); if (shortcut_size.x > 0.0f) { - ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); - ImGui::PopStyleColor(); + PopStyleColor(); } if (selected) @@ -8653,7 +8649,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) { - if (ImGui::MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) + if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) { if (p_selected) *p_selected = !*p_selected; @@ -8665,15 +8661,15 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool ImGui::BeginMainMenuBar() { ImGuiContext& g = *GImGui; - ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.FontBaseSize + g.Style.FramePadding.y * 2.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0)); - if (!ImGui::Begin("##MainMenuBar", NULL, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_MenuBar) - || !ImGui::BeginMenuBar()) + SetNextWindowPos(ImVec2(0.0f, 0.0f)); + SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.FontBaseSize + g.Style.FramePadding.y * 2.0f)); + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0)); + if (!Begin("##MainMenuBar", NULL, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_MenuBar) + || !BeginMenuBar()) { - ImGui::End(); - ImGui::PopStyleVar(2); + End(); + PopStyleVar(2); return false; } g.CurrentWindow->DC.MenuBarOffsetX += g.Style.DisplaySafeAreaPadding.x; @@ -8682,9 +8678,9 @@ bool ImGui::BeginMainMenuBar() void ImGui::EndMainMenuBar() { - ImGui::EndMenuBar(); - ImGui::End(); - ImGui::PopStyleVar(2); + EndMenuBar(); + End(); + PopStyleVar(2); } bool ImGui::BeginMenuBar() @@ -8696,14 +8692,14 @@ bool ImGui::BeginMenuBar() return false; IM_ASSERT(!window->DC.MenuBarAppending); - ImGui::BeginGroup(); // Save position - ImGui::PushID("##menubar"); + BeginGroup(); // Save position + PushID("##menubar"); ImRect rect = window->MenuBarRect(); PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->BorderSize + 0.5f)), ImVec2(ImFloor(rect.Max.x+0.5f), ImFloor(rect.Max.y+0.5f)), false); window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.MenuBarAppending = true; - ImGui::AlignFirstTextHeightToWidgets(); + AlignFirstTextHeightToWidgets(); return true; } @@ -8716,10 +8712,10 @@ void ImGui::EndMenuBar() IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); IM_ASSERT(window->DC.MenuBarAppending); PopClipRect(); - ImGui::PopID(); + PopID(); window->DC.MenuBarOffsetX = window->DC.CursorPos.x - window->MenuBarRect().Min.x; window->DC.GroupStack.back().AdvanceCursor = false; - ImGui::EndGroup(); + EndGroup(); window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.MenuBarAppending = false; } @@ -8748,22 +8744,22 @@ bool ImGui::BeginMenu(const char* label, bool enabled) { popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight()); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; - pressed = ImGui::Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); - ImGui::PopStyleVar(); - ImGui::SameLine(); + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + PopStyleVar(); + SameLine(); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); } else { popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame - float extra_w = ImMax(0.0f, ImGui::GetContentRegionAvail().x - w); - pressed = ImGui::Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); - if (!enabled) ImGui::PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w); + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + if (!enabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false); - if (!enabled) ImGui::PopStyleColor(); + if (!enabled) PopStyleColor(); } bool hovered = enabled && IsHovered(window->DC.LastItemRect, id); @@ -8810,17 +8806,17 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size) { // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. - ImGui::OpenPopup(label); + OpenPopup(label); return false; } menu_is_open |= want_open; if (want_open) - ImGui::OpenPopup(label); + OpenPopup(label); if (menu_is_open) { - ImGui::SetNextWindowPos(popup_pos, ImGuiSetCond_Always); + SetNextWindowPos(popup_pos, ImGuiSetCond_Always); ImGuiWindowFlags flags = ImGuiWindowFlags_ShowBorders | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu); menu_is_open = BeginPopupEx(label, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) } @@ -8830,7 +8826,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) void ImGui::EndMenu() { - ImGui::EndPopup(); + EndPopup(); } // A little colored square. Return true when clicked. @@ -8855,7 +8851,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde RenderFrame(bb.Min, bb.Max, GetColorU32(col), outline_border, style.FrameRounding); if (hovered) - ImGui::SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8(col.x), IM_F32_TO_INT8(col.y), IM_F32_TO_INT8(col.z), IM_F32_TO_INT8(col.z)); + SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8(col.x), IM_F32_TO_INT8(col.y), IM_F32_TO_INT8(col.z), IM_F32_TO_INT8(col.z)); return pressed; } @@ -8867,7 +8863,7 @@ bool ImGui::ColorEdit3(const char* label, float col[3]) col4[1] = col[1]; col4[2] = col[2]; col4[3] = 1.0f; - const bool value_changed = ImGui::ColorEdit4(label, col4, false); + const bool value_changed = ColorEdit4(label, col4, false); col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; @@ -8894,15 +8890,15 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) float f[4] = { col[0], col[1], col[2], col[3] }; if (edit_mode == ImGuiColorEditMode_HSV) - ImGui::ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); int i[4] = { IM_F32_TO_INT8(f[0]), IM_F32_TO_INT8(f[1]), IM_F32_TO_INT8(f[2]), IM_F32_TO_INT8(f[3]) }; int components = alpha ? 4 : 3; bool value_changed = false; - ImGui::BeginGroup(); - ImGui::PushID(label); + BeginGroup(); + PushID(label); const bool hsv = (edit_mode == 1); switch (edit_mode) @@ -8925,17 +8921,17 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) }; const char** fmt = hide_prefix ? fmt_table[0] : hsv ? fmt_table[2] : fmt_table[1]; - ImGui::PushItemWidth(w_item_one); + PushItemWidth(w_item_one); for (int n = 0; n < components; n++) { if (n > 0) - ImGui::SameLine(0, style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); if (n + 1 == components) - ImGui::PushItemWidth(w_item_last); - value_changed |= ImGui::DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]); + PushItemWidth(w_item_last); + value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]); } - ImGui::PopItemWidth(); - ImGui::PopItemWidth(); + PopItemWidth(); + PopItemWidth(); } break; case ImGuiColorEditMode_HEX: @@ -8947,8 +8943,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", i[0], i[1], i[2], i[3]); else ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", i[0], i[1], i[2]); - ImGui::PushItemWidth(w_slider_all - style.ItemInnerSpacing.x); - if (ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) + PushItemWidth(w_slider_all - style.ItemInnerSpacing.x); + if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) { value_changed |= true; char* p = buf; @@ -8960,24 +8956,24 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) else sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); } - ImGui::PopItemWidth(); + PopItemWidth(); } break; } - ImGui::SameLine(0, style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); const ImVec4 col_display(col[0], col[1], col[2], 1.0f); - if (ImGui::ColorButton(col_display)) + if (ColorButton(col_display)) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! // Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8(col[0]), IM_F32_TO_INT8(col[1]), IM_F32_TO_INT8(col[2]), IM_F32_TO_INT8(col[3])); + if (IsItemHovered()) + SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8(col[0]), IM_F32_TO_INT8(col[1]), IM_F32_TO_INT8(col[2]), IM_F32_TO_INT8(col[3])); if (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) { - ImGui::SameLine(0, style.ItemInnerSpacing.x); + SameLine(0, style.ItemInnerSpacing.x); const char* button_titles[3] = { "RGB", "HSV", "HEX" }; if (ButtonEx(button_titles[edit_mode], ImVec2(0,0), ImGuiButtonFlags_DontClosePopups)) g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away! @@ -8986,15 +8982,15 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) const char* label_display_end = FindRenderedTextEnd(label); if (label != label_display_end) { - ImGui::SameLine(0, (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) ? -1.0f : style.ItemInnerSpacing.x); - ImGui::TextUnformatted(label, label_display_end); + SameLine(0, (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) ? -1.0f : style.ItemInnerSpacing.x); + TextUnformatted(label, label_display_end); } // Convert back for (int n = 0; n < 4; n++) f[n] = i[n] / 255.0f; if (edit_mode == 1) - ImGui::ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); if (value_changed) { @@ -9005,8 +9001,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) col[3] = f[3]; } - ImGui::PopID(); - ImGui::EndGroup(); + PopID(); + EndGroup(); return value_changed; } @@ -9045,7 +9041,7 @@ void ImGui::Separator() ImGuiContext& g = *GImGui; if (g.LogEnabled) - ImGui::LogText(IM_NEWLINE "--------------------------------"); + LogText(IM_NEWLINE "--------------------------------"); if (window->DC.ColumnsCount > 1) { @@ -9103,7 +9099,7 @@ void ImGui::BeginGroup() void ImGui::EndGroup() { ImGuiWindow* window = GetCurrentWindow(); - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle& style = GetStyle(); IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls @@ -9180,14 +9176,14 @@ void ImGui::NextColumn() ImGuiContext& g = *GImGui; if (window->DC.ColumnsCount > 1) { - ImGui::PopItemWidth(); + PopItemWidth(); PopClipRect(); window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y); if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount) { // Columns 1+ cancel out IndentX - window->DC.ColumnsOffsetX = ImGui::GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x; + window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x; window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent); } else @@ -9203,7 +9199,7 @@ void ImGui::NextColumn() window->DC.CurrentLineTextBaseOffset = 0.0f; PushColumnClipRect(); - ImGui::PushItemWidth(ImGui::GetColumnWidth() * 0.65f); // FIXME: Move on columns setup + PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup } } @@ -9299,7 +9295,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) { if (window->DC.ColumnsCurrent != 0) ItemSize(ImVec2(0,0)); // Advance to column 0 - ImGui::PopItemWidth(); + PopItemWidth(); PopClipRect(); window->DrawList->ChannelsMerge(); @@ -9342,9 +9338,9 @@ void ImGui::Columns(int columns_count, const char* id, bool border) // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. - ImGui::PushID(0x11223347 + (id ? 0 : columns_count)); + PushID(0x11223347 + (id ? 0 : columns_count)); window->DC.ColumnsSetID = window->GetID(id ? id : "columns"); - ImGui::PopID(); + PopID(); // Set state for first column window->DC.ColumnsCurrent = 0; @@ -9373,7 +9369,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) } window->DrawList->ChannelsSplit(window->DC.ColumnsCount); PushColumnClipRect(); - ImGui::PushItemWidth(ImGui::GetColumnWidth() * 0.65f); + PushItemWidth(GetColumnWidth() * 0.65f); } else { @@ -9400,7 +9396,7 @@ void ImGui::Unindent(float indent_w) void ImGui::TreePush(const char* str_id) { ImGuiWindow* window = GetCurrentWindow(); - ImGui::Indent(); + Indent(); window->DC.TreeDepth++; PushID(str_id ? str_id : "#TreePush"); } @@ -9408,7 +9404,7 @@ void ImGui::TreePush(const char* str_id) void ImGui::TreePush(const void* ptr_id) { ImGuiWindow* window = GetCurrentWindow(); - ImGui::Indent(); + Indent(); window->DC.TreeDepth++; PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); } @@ -9416,7 +9412,7 @@ void ImGui::TreePush(const void* ptr_id) void ImGui::TreePushRawID(ImGuiID id) { ImGuiWindow* window = GetCurrentWindow(); - ImGui::Indent(); + Indent(); window->DC.TreeDepth++; window->IDStack.push_back(id); } @@ -9424,24 +9420,24 @@ void ImGui::TreePushRawID(ImGuiID id) void ImGui::TreePop() { ImGuiWindow* window = GetCurrentWindow(); - ImGui::Unindent(); + Unindent(); window->DC.TreeDepth--; PopID(); } void ImGui::Value(const char* prefix, bool b) { - ImGui::Text("%s: %s", prefix, (b ? "true" : "false")); + Text("%s: %s", prefix, (b ? "true" : "false")); } void ImGui::Value(const char* prefix, int v) { - ImGui::Text("%s: %d", prefix, v); + Text("%s: %d", prefix, v); } void ImGui::Value(const char* prefix, unsigned int v) { - ImGui::Text("%s: %d", prefix, v); + Text("%s: %d", prefix, v); } void ImGui::Value(const char* prefix, float v, const char* float_format) @@ -9450,33 +9446,33 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) { char fmt[64]; ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); - ImGui::Text(fmt, prefix, v); + Text(fmt, prefix, v); } else { - ImGui::Text("%s: %.3f", prefix, v); + Text("%s: %.3f", prefix, v); } } // FIXME: May want to remove those helpers? void ImGui::ValueColor(const char* prefix, const ImVec4& v) { - ImGui::Text("%s: (%.2f,%.2f,%.2f,%.2f)", prefix, v.x, v.y, v.z, v.w); - ImGui::SameLine(); - ImGui::ColorButton(v, true); + Text("%s: (%.2f,%.2f,%.2f,%.2f)", prefix, v.x, v.y, v.z, v.w); + SameLine(); + ColorButton(v, true); } void ImGui::ValueColor(const char* prefix, unsigned int v) { - ImGui::Text("%s: %08X", prefix, v); - ImGui::SameLine(); + Text("%s: %08X", prefix, v); + SameLine(); ImVec4 col; col.x = (float)((v >> 0) & 0xFF) / 255.0f; col.y = (float)((v >> 8) & 0xFF) / 255.0f; col.z = (float)((v >> 16) & 0xFF) / 255.0f; col.w = (float)((v >> 24) & 0xFF) / 255.0f; - ImGui::ColorButton(col, true); + ColorButton(col, true); } //----------------------------------------------------------------------------- From 9a751da136a4667564c73d678a8ff08587f14d19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 19:14:19 +0200 Subject: [PATCH 215/400] Caving in to ignoring stupid pedantic Clang warnings for old-style-cast in header files --- imgui.h | 9 +++++++++ imgui_internal.h | 23 ++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/imgui.h b/imgui.h index a3db5b06..a0a386ba 100644 --- a/imgui.h +++ b/imgui.h @@ -36,6 +36,11 @@ #define IM_PRINTFARGS(FMT) #endif +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif + // Forward declarations struct ImDrawChannel; // Temporary storage for outputting drawing commands out of order, used by ImDrawList::ChannelsSplit() struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call) @@ -1385,6 +1390,10 @@ struct ImFont IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. }; +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + //---- Include imgui_user.h at the end of imgui.h //---- So you can include code that extends ImGui using any of the types declared above. //---- (also convenient for user to only explicitly include vanilla imgui.h) diff --git a/imgui_internal.h b/imgui_internal.h index c67eab92..fa7fa980 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -19,6 +19,13 @@ #pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) #endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif + //----------------------------------------------------------------------------- // Forward Declarations //----------------------------------------------------------------------------- @@ -47,12 +54,6 @@ typedef int ImGuiSliderFlags; // enum ImGuiSliderFlags_ namespace ImGuiStb { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -#pragma clang diagnostic ignored "-Wmissing-prototypes" -#endif - #undef STB_TEXTEDIT_STRING #undef STB_TEXTEDIT_CHARTYPE #define STB_TEXTEDIT_STRING ImGuiTextEditState @@ -60,10 +61,6 @@ namespace ImGuiStb #define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f #include "stb_textedit.h" -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - } // namespace ImGuiStb //----------------------------------------------------------------------------- @@ -746,7 +743,11 @@ namespace ImGui IMGUI_API int ParseFormatPrecision(const char* fmt, int default_value); IMGUI_API float RoundScalar(float value, int decimal_precision); -} // namespace ImGuiP +} // namespace ImGui + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif #ifdef _MSC_VER #pragma warning (pop) From adb85d800d70d3ddc4548f0e8f184eede4568034 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 May 2016 19:16:44 +0200 Subject: [PATCH 216/400] Version 1.49 --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 90e6a24d..89fac50d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.49 WIP +// dear imgui, v1.49 // (main code and documentation) // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index a0a386ba..50971f94 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.49 WIP +// dear imgui, v1.49 // (headers) // See imgui.cpp file for documentation. @@ -16,7 +16,7 @@ #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.49 WIP" +#define IMGUI_VERSION "1.49" // Define attributes of all API symbols declarations, e.g. for DLL under Windows. #ifndef IMGUI_API diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d98b7fff..6ec0018e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.49 WIP +// dear imgui, v1.49 // (demo code) // Don't remove this file from your project! It is useful reference code that you can execute. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9f3c265b..63cf882a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.49 WIP +// dear imgui, v1.49 // (drawing and font code) // Contains implementation for diff --git a/imgui_internal.h b/imgui_internal.h index fa7fa980..c641c45e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.49 WIP +// dear imgui, v1.49 // (internals) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! From 5d4cf1c3f35834f05469147fb0aef8174c638334 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 30 May 2016 19:38:36 +0200 Subject: [PATCH 217/400] Version 1.50 WIP --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 89fac50d..c551dcd5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.49 +// dear imgui, v1.50 WIP // (main code and documentation) // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index 50971f94..57e58b90 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.49 +// dear imgui, v1.50 WIP // (headers) // See imgui.cpp file for documentation. @@ -16,7 +16,7 @@ #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.49" +#define IMGUI_VERSION "1.50 WIP" // Define attributes of all API symbols declarations, e.g. for DLL under Windows. #ifndef IMGUI_API diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6ec0018e..5117c7fc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.49 +// dear imgui, v1.50 WIP // (demo code) // Don't remove this file from your project! It is useful reference code that you can execute. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 63cf882a..03767096 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.49 +// dear imgui, v1.50 WIP // (drawing and font code) // Contains implementation for diff --git a/imgui_internal.h b/imgui_internal.h index c641c45e..a427a5fd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.49 +// dear imgui, v1.50 WIP // (internals) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! From 254a1a9e4c58dbc719cd8cc198ae6668a6aa8286 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 30 May 2016 20:00:20 +0200 Subject: [PATCH 218/400] InputText: Added support for CTRL+Backspace. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index c551dcd5..83a0ec5d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7756,7 +7756,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) { if (is_ctrl_down && !edit_state.HasSelection()) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Enter)) { bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; From d1c073a19981aa6c1bd0064e951d4b180d5e19f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 31 May 2016 00:00:44 +0200 Subject: [PATCH 219/400] Comments, tweaks --- README.md | 2 +- imgui.cpp | 9 ++++----- imgui_demo.cpp | 2 +- imgui_internal.h | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9e32e9e2..8a9eab15 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ ImGui is very programmer centric and the immediate-mode GUI paradigm might requi Is ImGui fast? -Probably fast enough for most uses. Down to the fundation of its visual design, ImGui is engineered to be fairly performant both in term of CPU and GPU usage. Running elaborate code and creating elaborate UI will of course have a cost but ImGui aims to minimize it. +Probably fast enough for most uses. Down to the foundation of its visual design, ImGui is engineered to be fairly performant both in term of CPU and GPU usage. Running elaborate code and creating elaborate UI will of course have a cost but ImGui aims to minimize it. Mileage may vary but the following screenshot can give you a rough idea of the cost of running and rendering UI code (In the case of a trivial demo application like this one, your driver/os setup are likely to be the bottleneck. Testing performance as part of a real application is recommended). diff --git a/imgui.cpp b/imgui.cpp index 83a0ec5d..3787d1b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -610,7 +610,6 @@ #include "imgui_internal.h" #include // toupper, isprint -#include // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf #include // NULL, malloc, free, qsort, atoi #include // vsnprintf, sscanf, printf #include // INT_MIN, INT_MAX @@ -9129,10 +9128,10 @@ void ImGui::EndGroup() } // Gets back to previous line and continue with horizontal layout -// pos_x == 0 : follow on previous item -// pos_x != 0 : align to specified column -// spacing_w < 0 : use default spacing if column_x==0, no spacing if column_x!=0 -// spacing_w >= 0 : enforce spacing +// pos_x == 0 : follow right after previous item +// pos_x != 0 : align to specified x position +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount void ImGui::SameLine(float pos_x, float spacing_w) { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5117c7fc..e7487f6b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -11,7 +11,7 @@ #include "imgui.h" #include // toupper, isprint -#include // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf +#include // sqrtf, powf, cosf, sinf, floorf, ceilf #include // vsnprintf, sscanf, printf #include // NULL, malloc, free, qsort, atoi #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier diff --git a/imgui_internal.h b/imgui_internal.h index a427a5fd..28fb93e9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -12,7 +12,7 @@ #endif #include // FILE* -#include // sqrtf() +#include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf #ifdef _MSC_VER #pragma warning (push) From 8291d7dc7c3d17425462e7aaf8593a4465405968 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 31 May 2016 22:34:48 +0200 Subject: [PATCH 220/400] Fixed minor bug introduced in 45dacbf084e897c317d034275fbd070ed71c0709 (#682) Actually minor because nobody uses that value. Still a terrible bug. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 3787d1b4..55eb344c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4202,7 +4202,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Update ContentsRegionMax. All the variable it depends on are set above in this function. window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x; - window->ContentsRegionRect.Min.x = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); + window->ContentsRegionRect.Min.y = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x)); window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y)); From 0f36ec9cb9c8a9ac192a2571f6dd9bfc9000b514 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 4 Jun 2016 14:48:08 +0100 Subject: [PATCH 221/400] Fixed a crash bug in stb_textedit.h (#681) --- stb_textedit.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_textedit.h b/stb_textedit.h index 3c300325..23f0f24e 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,4 +1,5 @@ // [ImGui] this is a slightly modified version of stb_truetype.h 1.8 +// [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) // [ImGui] - fixed some minor warnings // [ImGui] - added STB_TEXTEDIT_MOVEWORDLEFT/STB_TEXTEDIT_MOVEWORDRIGHT custom handler (#473) @@ -1095,7 +1096,7 @@ static void stb_textedit_discard_redo(StbUndoState *state) int n = state->undo_rec[k].insert_length, i; // delete n characters from all other records state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 - STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); + STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); for (i=state->redo_point; i < k; ++i) if (state->undo_rec[i].char_storage >= 0) state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 From d6a5fd06d7003568609042dd1df40b9457bafffb Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jun 2016 08:46:50 +0200 Subject: [PATCH 222/400] Demo: Added an extra 3-way columns demo --- imgui_demo.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e7487f6b..c890d75a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1312,7 +1312,22 @@ void ImGui::ShowTestWindow(bool* p_open) // Basic columns if (ImGui::TreeNode("Basic")) { - ImGui::Columns(4, "mycolumns"); + ImGui::Text("Without border:"); + ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border + ImGui::Separator(); + for (int n = 0; n < 14; n++) + { + char label[32]; + sprintf(label, "Item %d", n); + if (ImGui::Selectable(label)) {} + //if (ImGui::Button(label, ImVec2(-1,0))) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + + ImGui::Text("With border:"); + ImGui::Columns(4, "mycolumns"); // 4-ways, with border ImGui::Separator(); ImGui::Text("ID"); ImGui::NextColumn(); ImGui::Text("Name"); ImGui::NextColumn(); From 4fddfa4b5e27520ee8518e58af3cb53f26846943 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jun 2016 09:05:36 +0200 Subject: [PATCH 223/400] Demo: extra (somehow duplicate) Selectables+Columns demo --- imgui_demo.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c890d75a..752cd42b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -442,6 +442,19 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); ImGui::TreePop(); } + if (ImGui::TreeNode("In columns")) + { + ImGui::Columns(3, NULL, false); + static bool selected[16] = { 0 }; + for (int i = 0; i < 16; i++) + { + char label[32]; sprintf(label, "Item %d", i); + if (ImGui::Selectable(label, &selected[i])) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::TreePop(); + } if (ImGui::TreeNode("Grid")) { static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; From 65a525550ecf48e14f20681b081b1d9c8c136563 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jun 2016 09:14:54 +0200 Subject: [PATCH 224/400] ImFont: Allowing to use up to 0xFFFE glyphs in same font (increased from previous 0x8000) --- imgui.h | 2 +- imgui_draw.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index 57e58b90..f9442393 100644 --- a/imgui.h +++ b/imgui.h @@ -1357,7 +1357,7 @@ struct ImFont ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels ImVector Glyphs; // // All glyphs. ImVector IndexXAdvance; // // Sparse. Glyphs->XAdvance in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). - ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. + ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) float FallbackXAdvance; // == FallbackGlyph->XAdvance ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 03767096..5f485481 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1695,7 +1695,7 @@ void ImFont::BuildLookupTable() for (int i = 0; i != Glyphs.Size; i++) max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); - IM_ASSERT(Glyphs.Size < 32*1024); + IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved IndexXAdvance.clear(); IndexLookup.clear(); GrowIndex(max_codepoint + 1); @@ -1703,7 +1703,7 @@ void ImFont::BuildLookupTable() { int codepoint = (int)Glyphs[i].Codepoint; IndexXAdvance[codepoint] = Glyphs[i].XAdvance; - IndexLookup[codepoint] = (short)i; + IndexLookup[codepoint] = (unsigned short)i; } // Create a glyph to handle TAB @@ -1717,7 +1717,7 @@ void ImFont::BuildLookupTable() tab_glyph.Codepoint = '\t'; tab_glyph.XAdvance *= 4; IndexXAdvance[(int)tab_glyph.Codepoint] = (float)tab_glyph.XAdvance; - IndexLookup[(int)tab_glyph.Codepoint] = (short)(Glyphs.Size-1); + IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1); } FallbackGlyph = NULL; @@ -1745,7 +1745,7 @@ void ImFont::GrowIndex(int new_size) for (int i = old_size; i < new_size; i++) { IndexXAdvance[i] = -1.0f; - IndexLookup[i] = (short)-1; + IndexLookup[i] = (unsigned short)-1; } } @@ -1754,13 +1754,13 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. int index_size = IndexLookup.Size; - if (dst < index_size && IndexLookup.Data[dst] == -1 && !overwrite_dst) // 'dst' already exists + if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists return; if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op return; GrowIndex(dst + 1); - IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : -1; + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1; IndexXAdvance[dst] = (src < index_size) ? IndexXAdvance.Data[src] : 1.0f; } @@ -1768,8 +1768,8 @@ const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const { if (c < IndexLookup.Size) { - const short i = IndexLookup[c]; - if (i != -1) + const unsigned short i = IndexLookup[c]; + if (i != (unsigned short)-1) return &Glyphs.Data[i]; } return FallbackGlyph; From 2da30e8702f9242a1af5a1e6c1bc2fa00170cd12 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 11 Jun 2016 09:28:20 +0200 Subject: [PATCH 225/400] Comments (#691) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index f9442393..7f8d904b 100644 --- a/imgui.h +++ b/imgui.h @@ -1268,7 +1268,7 @@ struct ImFontConfig int FontNo; // 0 // Index of font within TTF file float SizePixels; // // Size in pixels for rasterizer int OversampleH, OversampleV; // 3, 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. - bool PixelSnapH; // false // Align every character to pixel boundary (if enabled, set OversampleH/V to 1) + bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs const ImWchar* GlyphRanges; // // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). From 3fd3eac3707550117f5c6f02987dd61704b3abe4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 11 Jun 2016 10:23:37 +0200 Subject: [PATCH 226/400] Fixed TextWrapped() override wrap position is one is already set (#690) --- imgui.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 55eb344c..d71e611a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -460,7 +460,7 @@ - doc: add a proper documentation+regression testing system (#435) - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. - - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). + - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis) (#690) - window: auto-fit feedback loop when user relies on any dynamic layout (window width multiplier, column) appears weird to end-user. clarify. - window: allow resizing of child windows (possibly given min/max for each axis?) - window: background options for child windows, border option (disable rounding) @@ -5245,9 +5245,10 @@ void ImGui::TextDisabled(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - PushTextWrapPos(0.0f); + bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set + if (need_wrap) PushTextWrapPos(0.0f); TextV(fmt, args); - PopTextWrapPos(); + if (need_wrap) PopTextWrapPos(); } void ImGui::TextWrapped(const char* fmt, ...) From d79186931e663941f41aad7bb05c8b8f5f538ed9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 11 Jun 2016 15:42:10 +0200 Subject: [PATCH 227/400] ImDrawList: Fixed a (rarely occuring) bug with merging with previous command + unnecessary OverlayDrawList command --- imgui.cpp | 1 - imgui_draw.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d71e611a..9e392d30 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2066,7 +2066,6 @@ void ImGui::NewFrame() g.OverlayDrawList.Clear(); g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID); g.OverlayDrawList.PushClipRectFullScreen(); - g.OverlayDrawList.AddDrawCmd(); // Mark rendering data as invalid to prevent user who may have a handle on it to use it g.RenderDrawData.Valid = false; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5f485481..ba20abc8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -196,7 +196,7 @@ void ImDrawList::UpdateClipRect() // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; - if (prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) + if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) CmdBuffer.pop_back(); else curr_cmd->ClipRect = curr_clip_rect; From 9f21c7189f92469809529b28ac4753caf31fed62 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 12 Jun 2016 12:23:16 +0200 Subject: [PATCH 228/400] TextUnformatted() fixed clipping bug in the large-text path when horizontal scroll has been applied (#692, #246) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 9e392d30..0c89bf3e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5310,7 +5310,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // Lines to render if (line < text_end) { - ImRect line_rect(pos, pos + ImVec2(GetWindowWidth(), line_height)); + ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); while (line < text_end) { const char* line_end = strchr(line, '\n'); @@ -9675,6 +9675,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) return; NodeDrawList(window->DrawList, "DrawList"); + ImGui::BulletText("Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); From f83790dc5a241325cb54a048d53116e7fd1f884f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 12 Jun 2016 12:23:20 +0200 Subject: [PATCH 229/400] Comments --- imgui.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 7f8d904b..e806f498 100644 --- a/imgui.h +++ b/imgui.h @@ -693,9 +693,9 @@ enum ImGuiMouseCursor_ enum ImGuiSetCond_ { ImGuiSetCond_Always = 1 << 0, // Set the variable - ImGuiSetCond_Once = 1 << 1, // Only set the variable on the first call per runtime session - ImGuiSetCond_FirstUseEver = 1 << 2, // Only set the variable if the window doesn't exist in the .ini file - ImGuiSetCond_Appearing = 1 << 3 // Only set the variable if the window is appearing after being inactive (or the first time) + ImGuiSetCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call with succeed) + ImGuiSetCond_FirstUseEver = 1 << 2, // Set the variable if the window has no saved data (if doesn't exist in the .ini file) + ImGuiSetCond_Appearing = 1 << 3 // Set the variable if the window is appearing after being hidden/inactive (or the first time) }; struct ImGuiStyle From c4db79f34baab154df9882b67a1404be00d11fd5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 12 Jun 2016 22:27:15 +0200 Subject: [PATCH 230/400] Member variable name renamed "ID" "Id" for casing consistency --- imgui.cpp | 46 +++++++++++++++++++++++----------------------- imgui_internal.h | 18 +++++++++--------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0c89bf3e..e0fca101 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1695,7 +1695,7 @@ ImGuiWindow::ImGuiWindow(const char* name) Name = ImStrdup(name); ID = ImHash(name, 0); IDStack.push_back(ID); - MoveID = GetID("#MOVE"); + MoveId = GetID("#MOVE"); Flags = 0; IndexWithinParent = 0; @@ -1714,7 +1714,7 @@ ImGuiWindow::ImGuiWindow(const char* name) Collapsed = false; SkipItems = false; BeginCount = 0; - PopupID = 0; + PopupId = 0; AutoFitFramesX = AutoFitFramesY = -1; AutoFitOnlyGrows = false; AutoPosLastDirection = -1; @@ -1839,7 +1839,7 @@ void ImGui::ItemSize(const ImRect& bb, float text_offset_y) bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.LastItemID = id ? *id : 0; + window->DC.LastItemId = id ? *id : 0; window->DC.LastItemRect = bb; window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; if (IsClippedEx(bb, id, false)) @@ -1853,7 +1853,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) // So that clicking on items with no active id such as Text() still returns true with IsItemHovered() window->DC.LastItemHoveredRect = true; if (g.HoveredRootWindow == window->RootWindow) - if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdAllowOverlap || (g.ActiveId == window->MoveID)) + if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdAllowOverlap || (g.ActiveId == window->MoveId)) if (IsWindowContentHoverable(window)) window->DC.LastItemHoveredAndUsable = true; } @@ -2132,7 +2132,7 @@ void ImGui::NewFrame() { KeepAliveID(g.MovedWindowMoveId); IM_ASSERT(g.MovedWindow && g.MovedWindow->RootWindow); - IM_ASSERT(g.MovedWindow->RootWindow->MoveID == g.MovedWindowMoveId); + IM_ASSERT(g.MovedWindow->RootWindow->MoveId == g.MovedWindowMoveId); if (g.IO.MouseDown[0]) { if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoMove)) @@ -2337,7 +2337,7 @@ static ImGuiIniData* FindWindowSettings(const char* name) for (int i = 0; i != g.Settings.Size; i++) { ImGuiIniData* ini = &g.Settings[i]; - if (ini->ID == id) + if (ini->Id == id) return ini; } return NULL; @@ -2348,7 +2348,7 @@ static ImGuiIniData* AddWindowSettings(const char* name) GImGui->Settings.resize(GImGui->Settings.Size + 1); ImGuiIniData* ini = &GImGui->Settings.back(); ini->Name = ImStrdup(name); - ini->ID = ImHash(name, 0); + ini->Id = ImHash(name, 0); ini->Collapsed = false; ini->Pos = ImVec2(FLT_MAX,FLT_MAX); ini->Size = ImVec2(0,0); @@ -2579,7 +2579,7 @@ void ImGui::EndFrame() if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove)) { g.MovedWindow = g.HoveredWindow; - g.MovedWindowMoveId = g.HoveredRootWindow->MoveID; + g.MovedWindowMoveId = g.HoveredRootWindow->MoveId; SetActiveID(g.MovedWindowMoveId, g.HoveredRootWindow); } } @@ -3211,7 +3211,7 @@ bool ImGui::IsItemActive() if (g.ActiveId) { ImGuiWindow* window = GetCurrentWindowRead(); - return g.ActiveId == window->DC.LastItemID; + return g.ActiveId == window->DC.LastItemId; } return false; } @@ -3242,9 +3242,9 @@ bool ImGui::IsItemVisible() void ImGui::SetItemAllowOverlap() { ImGuiContext& g = *GImGui; - if (g.HoveredId == g.CurrentWindow->DC.LastItemID) + if (g.HoveredId == g.CurrentWindow->DC.LastItemId) g.HoveredIdAllowOverlap = true; - if (g.ActiveId == g.CurrentWindow->DC.LastItemID) + if (g.ActiveId == g.CurrentWindow->DC.LastItemId) g.ActiveIdAllowOverlap = true; } @@ -3312,7 +3312,7 @@ void ImGui::EndTooltip() static bool IsPopupOpen(ImGuiID id) { ImGuiContext& g = *GImGui; - const bool is_open = g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupID == id; + const bool is_open = g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; return is_open; } @@ -3329,7 +3329,7 @@ void ImGui::OpenPopupEx(const char* str_id, bool reopen_existing) ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) if (g.OpenPopupStack.Size < current_stack_size + 1) g.OpenPopupStack.push_back(popup_ref); - else if (reopen_existing || g.OpenPopupStack[current_stack_size].PopupID != id) + else if (reopen_existing || g.OpenPopupStack[current_stack_size].PopupId != id) { g.OpenPopupStack.resize(current_stack_size+1); g.OpenPopupStack[current_stack_size] = popup_ref; @@ -3405,7 +3405,7 @@ void ImGui::CloseCurrentPopup() { ImGuiContext& g = *GImGui; int popup_idx = g.CurrentPopupStack.Size - 1; - if (popup_idx < 0 || popup_idx > g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupID != g.OpenPopupStack[popup_idx].PopupID) + if (popup_idx < 0 || popup_idx > g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) return; while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu)) popup_idx--; @@ -3808,11 +3808,11 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size]; - window_was_active &= (window->PopupID == popup_ref.PopupID); + window_was_active &= (window->PopupId == popup_ref.PopupId); window_was_active &= (window == popup_ref.Window); popup_ref.Window = window; g.CurrentPopupStack.push_back(popup_ref); - window->PopupID = popup_ref.PopupID; + window->PopupId = popup_ref.PopupId; } const bool window_appearing_after_being_hidden = (window->HiddenFrames == 1); @@ -9221,7 +9221,7 @@ static float GetDraggedColumnOffset(int column_index) ImGuiContext& g = *GImGui; ImGuiWindow* window = ImGui::GetCurrentWindowRead(); IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets. - IM_ASSERT(g.ActiveId == window->DC.ColumnsSetID + ImGuiID(column_index)); + IM_ASSERT(g.ActiveId == window->DC.ColumnsSetId + ImGuiID(column_index)); float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x; x = ImClamp(x, ImGui::GetColumnOffset(column_index-1)+g.Style.ColumnsMinSpacing, ImGui::GetColumnOffset(column_index+1)-g.Style.ColumnsMinSpacing); @@ -9238,7 +9238,7 @@ float ImGui::GetColumnOffset(int column_index) if (g.ActiveId) { - const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index); + const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index); if (g.ActiveId == column_id) return GetDraggedColumnOffset(column_index); } @@ -9259,7 +9259,7 @@ void ImGui::SetColumnOffset(int column_index, float offset) const float t = (offset - window->DC.ColumnsMinX) / (window->DC.ColumnsMaxX - window->DC.ColumnsMinX); window->DC.ColumnsData[column_index].OffsetNorm = t; - const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index); + const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index); window->DC.StateStorage->SetFloat(column_id, t); } @@ -9310,7 +9310,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) for (int i = 1; i < window->DC.ColumnsCount; i++) { float x = window->Pos.x + GetColumnOffset(i); - const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i); + const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(i); const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2)); if (IsClippedEx(column_rect, &column_id, false)) continue; @@ -9338,7 +9338,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. PushID(0x11223347 + (id ? 0 : columns_count)); - window->DC.ColumnsSetID = window->GetID(id ? id : "columns"); + window->DC.ColumnsSetId = window->GetID(id ? id : "columns"); PopID(); // Set state for first column @@ -9360,7 +9360,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) window->DC.ColumnsData.resize(columns_count + 1); for (int column_index = 0; column_index < columns_count + 1; column_index++) { - const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index); + const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index); KeepAliveID(column_id); const float default_t = column_index / (float)window->DC.ColumnsCount; const float t = window->DC.StateStorage->GetFloat(column_id, default_t); // Cheaply store our floating point value inside the integer (could store an union into the map?) @@ -9696,7 +9696,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) for (int i = 0; i < g.OpenPopupStack.Size; i++) { ImGuiWindow* window = g.OpenPopupStack[i].Window; - ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupID, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); + ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); } ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index 28fb93e9..e19f3e42 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -312,7 +312,7 @@ struct IMGUI_API ImGuiTextEditState struct ImGuiIniData { char* Name; - ImGuiID ID; + ImGuiID Id; ImVec2 Pos; ImVec2 Size; bool Collapsed; @@ -331,13 +331,13 @@ struct ImGuiMouseCursorData // Storage for current popup stack struct ImGuiPopupRef { - ImGuiID PopupID; // Set on OpenPopup() + ImGuiID PopupId; // Set on OpenPopup() ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() ImGuiWindow* ParentWindow; // Set on OpenPopup() ImGuiID ParentMenuSet; // Set on OpenPopup() ImVec2 MousePosOnOpen; // Copy of mouse position at the time of opening popup - ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } + ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupId = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } }; // Main state for ImGui @@ -522,7 +522,7 @@ struct IMGUI_API ImGuiDrawContext float PrevLineTextBaseOffset; float LogLinePosY; int TreeDepth; - ImGuiID LastItemID; + ImGuiID LastItemId; ImRect LastItemRect; bool LastItemHoveredAndUsable; // Item rectangle is hovered, and its window is currently interactable with (not blocked by a popup preventing access to the window) bool LastItemHoveredRect; // Item rectangle is hovered, but its window may or not be currently interactable with (might be blocked by a popup preventing access to the window) @@ -555,7 +555,7 @@ struct IMGUI_API ImGuiDrawContext float ColumnsCellMinY; float ColumnsCellMaxY; bool ColumnsShowBorders; - ImGuiID ColumnsSetID; + ImGuiID ColumnsSetId; ImVector ColumnsData; ImGuiDrawContext() @@ -565,7 +565,7 @@ struct IMGUI_API ImGuiDrawContext CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; LogLinePosY = -1.0f; TreeDepth = 0; - LastItemID = 0; + LastItemId = 0; LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f); LastItemHoveredAndUsable = LastItemHoveredRect = false; MenuBarAppending = false; @@ -587,7 +587,7 @@ struct IMGUI_API ImGuiDrawContext ColumnsStartPosY = 0.0f; ColumnsCellMinY = ColumnsCellMaxY = 0.0f; ColumnsShowBorders = true; - ColumnsSetID = 0; + ColumnsSetId = 0; } }; @@ -606,7 +606,7 @@ struct IMGUI_API ImGuiWindow ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize() ImRect ContentsRegionRect; // Maximum visible content position in window coordinates. ~~ (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis ImVec2 WindowPadding; // Window padding at the time of begin. We need to lock it, in particular manipulation of the ShowBorder would have an effect - ImGuiID MoveID; // == window->GetID("#MOVE") + ImGuiID MoveId; // == window->GetID("#MOVE") ImVec2 Scroll; ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered @@ -619,7 +619,7 @@ struct IMGUI_API ImGuiWindow bool Collapsed; // Set when collapsing window to become only title-bar bool SkipItems; // == Visible && !Collapsed int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) - ImGuiID PopupID; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) + ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) int AutoFitFramesX, AutoFitFramesY; bool AutoFitOnlyGrows; int AutoPosLastDirection; From 9cb271f4c856c41ecd305882885308836e988834 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jun 2016 23:09:40 +0200 Subject: [PATCH 231/400] Fixed minor text clipping issue in window title for when using font straying above usual line (#699) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index e0fca101..e67f5a90 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4265,7 +4265,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; - RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, NULL, &clip_max); + ImVec2 clip_min = ImVec2(text_min.x, window->Pos.y); + RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_min, &clip_max); } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() From 92bff4c8d7cbb7505ce06d33d7e10958ce710e1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jun 2016 23:09:48 +0200 Subject: [PATCH 232/400] ColorEdit4(): better preserve inputting value out of 0..255 range, display then clamped in Hexadecimal form --- imgui.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e67f5a90..5cfe3653 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -863,7 +863,8 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) // HELPERS //----------------------------------------------------------------------------- -#define IM_F32_TO_INT8(_VAL) ((int)((_VAL) * 255.0f + 0.5f)) +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. #ifdef _WIN32 @@ -1184,10 +1185,10 @@ ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) { ImU32 out; - out = ((ImU32)IM_F32_TO_INT8(ImSaturate(in.x))); - out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.y))) << 8; - out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.z))) << 16; - out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.w))) << 24; + out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)); + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << 8; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << 16; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << 24; return out; } @@ -7944,8 +7945,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 { edit_state.CursorAnim += g.IO.DeltaTime; - // We need to: - // - Display the text (this can be more easily clipped) + // This is going to be messy. We need to: + // - Display the text (this alone can be more easily clipped) // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) // - Measure text height (for scrollbar) // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) @@ -8110,14 +8111,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) { IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() - bool ret = InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); - return ret; + return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); } bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data) { - bool ret = InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); - return ret; + return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); } // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "display_format" argument) @@ -8851,7 +8850,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde RenderFrame(bb.Min, bb.Max, GetColorU32(col), outline_border, style.FrameRounding); if (hovered) - SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8(col.x), IM_F32_TO_INT8(col.y), IM_F32_TO_INT8(col.z), IM_F32_TO_INT8(col.z)); + SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8_SAT(col.x), IM_F32_TO_INT8_SAT(col.y), IM_F32_TO_INT8_SAT(col.z), IM_F32_TO_INT8_SAT(col.z)); return pressed; } @@ -8892,7 +8891,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) if (edit_mode == ImGuiColorEditMode_HSV) ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); - int i[4] = { IM_F32_TO_INT8(f[0]), IM_F32_TO_INT8(f[1]), IM_F32_TO_INT8(f[2]), IM_F32_TO_INT8(f[3]) }; + int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; int components = alpha ? 4 : 3; bool value_changed = false; @@ -8969,7 +8968,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) // Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here if (IsItemHovered()) - SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8(col[0]), IM_F32_TO_INT8(col[1]), IM_F32_TO_INT8(col[2]), IM_F32_TO_INT8(col[3])); + SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8_SAT(col[0]), IM_F32_TO_INT8_SAT(col[1]), IM_F32_TO_INT8_SAT(col[2]), IM_F32_TO_INT8_SAT(col[3])); if (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton) { From 4621b357c1c6d9d4c4872c8bf45bb81ba0724ca0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 19 Jun 2016 12:50:22 +0200 Subject: [PATCH 233/400] Wrapped text: fixed incorrect testing for negative wrap coordinates, they are perfectly legal. (#706) --- imgui.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5cfe3653..9e21d0b2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1946,8 +1946,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) else if (wrap_pos_x > 0.0f) wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space - const float wrap_width = wrap_pos_x > 0.0f ? ImMax(wrap_pos_x - pos.x, 0.00001f) : 0.0f; - return wrap_width; + return ImMax(wrap_pos_x - pos.x, 1.0f); } //----------------------------------------------------------------------------- @@ -5356,9 +5355,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); // Account of baseline offset - ImVec2 text_pos = window->DC.CursorPos; - text_pos.y += window->DC.CurrentLineTextBaseOffset; - + ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset); ImRect bb(text_pos, text_pos + text_size); ItemSize(text_size); if (!ItemAdd(bb, NULL)) From 2f4e2eec68975c42c3b0b63d3babaa6a4a0b31f9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 25 Jun 2016 13:54:34 +0200 Subject: [PATCH 234/400] InputText, ImGuiTextFilter: using strncpy instead of printf("%s"). --- imgui.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9e21d0b2..7a755a27 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -895,6 +895,13 @@ int ImStrnicmp(const char* str1, const char* str2, int count) return d; } +void ImStrncpy(char* dst, const char* src, int count) +{ + if (count < 1) return; + strncpy(dst, src, (size_t)count); + dst[count-1] = 0; +} + char* ImStrdup(const char *str) { size_t len = strlen(str) + 1; @@ -1431,7 +1438,7 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) { if (default_filter) { - ImFormatString(InputBuf, IM_ARRAYSIZE(InputBuf), "%s", default_filter); + ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); Build(); } else @@ -7631,9 +7638,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) const int prev_len_w = edit_state.CurLenW; - edit_state.Text.resize(buf_size+1); // wchar count <= utf-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash. - edit_state.InitialText.resize(buf_size+1); // utf-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash. - ImFormatString(edit_state.InitialText.Data, edit_state.InitialText.Size, "%s", buf); + edit_state.Text.resize(buf_size+1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash. + edit_state.InitialText.resize(buf_size+1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash. + ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size); const char* buf_end = NULL; edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end); edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. @@ -7839,7 +7846,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Restore initial value if (is_editable) { - ImFormatString(buf, buf_size, "%s", edit_state.InitialText.Data); + ImStrncpy(buf, edit_state.InitialText.Data, buf_size); value_changed = true; } } @@ -7925,7 +7932,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Copy back to user buffer if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0) { - ImFormatString(buf, buf_size, "%s", edit_state.TempTextBuffer.Data); + ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size); value_changed = true; } } From 13615a1318364addbc7c80c464f21650bb2b2272 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 25 Jun 2016 13:57:05 +0200 Subject: [PATCH 235/400] InputText: render currently edited buffer from the internal buffer, toward #701 --- imgui.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7a755a27..225714c0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7938,10 +7938,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 } } + // Render + // Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on. + const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL; + if (!is_multiline) RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - // Render const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; ImVec2 text_size(0.f, 0.f); @@ -8067,7 +8070,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 } } - draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf, buf+edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect); + draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect); // Draw blinking cursor bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f; @@ -8085,8 +8088,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Render text only const char* buf_end = NULL; if (is_multiline) - text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf, &buf_end) * g.FontSize); // We don't need width - draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf, buf_end, 0.0f, is_multiline ? NULL : &clip_rect); + text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width + draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect); } if (is_multiline) @@ -8101,7 +8104,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Log as text if (g.LogEnabled && !is_password) - LogRenderedText(render_pos, buf, NULL); + LogRenderedText(render_pos, buf_display, NULL); if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); From 3c8e4907788f5186b56fe936bdd44ac2bcad2a70 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 25 Jun 2016 14:28:58 +0200 Subject: [PATCH 236/400] Comment on dealing with io.WantCaptureKeyboard (#703) --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 225714c0..ba9eb69a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -391,10 +391,12 @@ e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! Q: How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application? - A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame. + A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame, but either should be fine. When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application. When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available. ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is a more accurate and complete than testing for ImGui::IsMouseHoveringAnyWindow(). + (Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically have 'io.WantcaptureKeyboard=false'. Depending + on your application logic it may or not be inconvenient. You might want to track which key-downs were for ImGui (e.g. with an array of bool) and filter out the corresponding key-ups. Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) A: Use the font atlas to load the TTF file you want: From 355dae5d999f597bc0c90a28b0522f1316bd6d96 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 25 Jun 2016 14:37:14 +0200 Subject: [PATCH 237/400] Comments amend 3c8e4907788f5186b56fe936bdd44ac2bcad2a70 (committed before saving last comment edit) (#703) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ba9eb69a..de0e32df 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -395,8 +395,8 @@ When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application. When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available. ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is a more accurate and complete than testing for ImGui::IsMouseHoveringAnyWindow(). - (Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically have 'io.WantcaptureKeyboard=false'. Depending - on your application logic it may or not be inconvenient. You might want to track which key-downs were for ImGui (e.g. with an array of bool) and filter out the corresponding key-ups. + (Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically have 'io.WantcaptureKeyboard=false'. + Depending on your application logic it may or not be inconvenient. You might want to track which key-downs were for ImGui (e.g. with an array of bool) and filter out the corresponding key-ups.) Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) A: Use the font atlas to load the TTF file you want: From de61fcc619606788693092ba00279a787c0181e1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 25 Jun 2016 17:03:49 +0200 Subject: [PATCH 238/400] Minor bits --- imgui.cpp | 5 ++--- imgui.h | 2 +- imgui_demo.cpp | 12 ++++++------ imgui_internal.h | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index de0e32df..8e12e86b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4916,8 +4916,7 @@ void ImGui::SetWindowFocus(const char* name) { if (name) { - ImGuiWindow* window = FindWindowByName(name); - if (window) + if (ImGuiWindow* window = FindWindowByName(name)) FocusWindow(window); } else @@ -9470,7 +9469,7 @@ void ImGui::ValueColor(const char* prefix, const ImVec4& v) ColorButton(v, true); } -void ImGui::ValueColor(const char* prefix, unsigned int v) +void ImGui::ValueColor(const char* prefix, ImU32 v) { Text("%s: %08X", prefix, v); SameLine(); diff --git a/imgui.h b/imgui.h index e806f498..805aa996 100644 --- a/imgui.h +++ b/imgui.h @@ -352,7 +352,7 @@ namespace ImGui IMGUI_API void Value(const char* prefix, unsigned int v); IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); IMGUI_API void ValueColor(const char* prefix, const ImVec4& v); - IMGUI_API void ValueColor(const char* prefix, unsigned int v); + IMGUI_API void ValueColor(const char* prefix, ImU32 v); // Tooltips IMGUI_API void SetTooltip(const char* fmt, ...) IM_PRINTFARGS(1); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 752cd42b..67846e7a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1020,24 +1020,24 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::Text("Hello\nWorld"); ImGui::SameLine(); ImGui::Text("One\nTwo\nThree"); - ImGui::Button("HOP"); ImGui::SameLine(); + ImGui::Button("HOP##1"); ImGui::SameLine(); ImGui::Text("Banana"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine(); ImGui::Text("Banana"); - ImGui::Button("HOP"); ImGui::SameLine(); + ImGui::Button("HOP##2"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine(); ImGui::Text("Banana"); - ImGui::Button("TEST"); ImGui::SameLine(); + ImGui::Button("TEST##1"); ImGui::SameLine(); ImGui::Text("TEST"); ImGui::SameLine(); - ImGui::SmallButton("TEST"); + ImGui::SmallButton("TEST##2"); ImGui::AlignFirstTextHeightToWidgets(); // If your line starts with text, call this to align it to upcoming widgets. ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); - ImGui::Button("Widget"); ImGui::SameLine(); + ImGui::Button("Widget##1"); ImGui::SameLine(); ImGui::Text("Widget"); ImGui::SameLine(); - ImGui::SmallButton("Widget"); + ImGui::SmallButton("Widget##2"); // Tree const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; diff --git a/imgui_internal.h b/imgui_internal.h index e19f3e42..8cc895f2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -481,7 +481,7 @@ struct ImGuiContext ScalarAsInputTextId = 0; DragCurrentValue = 0.0f; DragLastMouseDelta = ImVec2(0.0f, 0.0f); - DragSpeedDefaultRatio = 0.01f; + DragSpeedDefaultRatio = 1.0f / 100.0f; DragSpeedScaleSlow = 0.01f; DragSpeedScaleFast = 10.0f; ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); @@ -643,7 +643,7 @@ struct IMGUI_API ImGuiWindow ImGuiWindow* RootNonPopupWindow; // If we are a child window, this is pointing to the first non-child non-popup parent window. Else point to ourself. ImGuiWindow* ParentWindow; // If we are a child window, this is pointing to our parent window. Else point to NULL. - // Focus + // Navigation / Focus int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through) int FocusIdxAllRequestCurrent; // Item being requested for focus From e06852abaf2a59bb376890fe65e6429b040354a7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 26 Jun 2016 13:24:30 +0200 Subject: [PATCH 239/400] Fixed Windows default clipboard leaving its buffer unfreed on application's exit. (#714) --- imgui.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8e12e86b..f9bfdd2f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9501,12 +9501,8 @@ void ImGui::ValueColor(const char* prefix, ImU32 v) static const char* GetClipboardTextFn_DefaultImpl() { - static char* buf_local = NULL; - if (buf_local) - { - ImGui::MemFree(buf_local); - buf_local = NULL; - } + static ImVector buf_local; + buf_local.clear(); if (!OpenClipboard(NULL)) return NULL; HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT); @@ -9515,19 +9511,18 @@ static const char* GetClipboardTextFn_DefaultImpl() if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle)) { int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; - buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char)); - ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL); + buf_local.resize(buf_len); + ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL); } GlobalUnlock(wbuf_handle); CloseClipboard(); - return buf_local; + return buf_local.Data; } static void SetClipboardTextFn_DefaultImpl(const char* text) { if (!OpenClipboard(NULL)) return; - const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); if (wbuf_handle == NULL) From c36fd541ad641f3bf6aaa2d311f327c3846ac296 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jun 2016 09:56:45 +0200 Subject: [PATCH 240/400] InputTextMultiline(): Fixed Ctrl+DownArrow moving scrolling out of bounds --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f9bfdd2f..19fb9bdf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7757,8 +7757,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y - g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); } else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } @@ -9679,6 +9679,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; NodeDrawList(window->DrawList, "DrawList"); ImGui::BulletText("Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); + ImGui::BulletText("Scroll: (%.2f,%.2f)", window->Scroll.x, window->Scroll.y); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); From ba7acdac476b22fdb5c08326f9ed93d2ff37f78b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jun 2016 12:59:49 +0200 Subject: [PATCH 241/400] Added assert to track stb_textedit.h issue (#715) --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 19fb9bdf..e411fe09 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7406,6 +7406,7 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) { const int text_len = obj->CurLenW; + IM_ASSERT(pos <= text_len); if (new_text_len + text_len + 1 > obj->Text.Size) return false; From 297bb3fc92e74942c04fa365b644d267b2bf7e62 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jun 2016 09:53:02 +0200 Subject: [PATCH 242/400] NextColumn() tidying up with a sane early out --- imgui.cpp | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e411fe09..904cef81 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9178,37 +9178,34 @@ void ImGui::NewLine() void ImGui::NextColumn() { ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) + if (window->SkipItems || window->DC.ColumnsCount <= 1) return; ImGuiContext& g = *GImGui; - if (window->DC.ColumnsCount > 1) + PopItemWidth(); + PopClipRect(); + + window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y); + if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount) { - PopItemWidth(); - PopClipRect(); - - window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y); - if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount) - { - // Columns 1+ cancel out IndentX - window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x; - window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent); - } - else - { - window->DC.ColumnsCurrent = 0; - window->DC.ColumnsOffsetX = 0.0f; - window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY; - window->DrawList->ChannelsSetCurrent(0); - } - window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX); - window->DC.CursorPos.y = window->DC.ColumnsCellMinY; - window->DC.CurrentLineHeight = 0.0f; - window->DC.CurrentLineTextBaseOffset = 0.0f; - - PushColumnClipRect(); - PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup + // Columns 1+ cancel out IndentX + window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x; + window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent); } + else + { + window->DC.ColumnsCurrent = 0; + window->DC.ColumnsOffsetX = 0.0f; + window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY; + window->DrawList->ChannelsSetCurrent(0); + } + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX); + window->DC.CursorPos.y = window->DC.ColumnsCellMinY; + window->DC.CurrentLineHeight = 0.0f; + window->DC.CurrentLineTextBaseOffset = 0.0f; + + PushColumnClipRect(); + PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup } int ImGui::GetColumnIndex() From 74bbfcfaa668fd0e35b41c04b18f7a15f5419833 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jun 2016 10:07:36 +0200 Subject: [PATCH 243/400] ImGuiListClipper: fixed automatic-height calc path dumbly having user display element 0 twice (#661, #716) First bug out of two. Was easily visible using e.g. 50% alpha text. --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 904cef81..a9f9dbaa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1680,8 +1680,9 @@ bool ImGuiListClipper::Step() if (ItemsCount == 1) { ItemsCount = -1; return false; } float items_height = ImGui::GetCursorPosY() - StartPosY; IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically - ImGui::SetCursorPosY(StartPosY); // Rewind cursor so we can Begin() again, this time with a known height. - Begin(ItemsCount, items_height); + Begin(ItemsCount-1, items_height); + DisplayStart++; + DisplayEnd++; StepNo = 3; return true; } From b9b3dec7da27b87cbb07a75542a0df07bf013491 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jun 2016 10:19:01 +0200 Subject: [PATCH 244/400] ImGuiListClipper: Fix to behave within column (#661, #662, #716) --- imgui.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a9f9dbaa..3486458b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1622,12 +1622,14 @@ float ImGuiSimpleColumns::CalcExtraSpace(float avail_w) static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) { - // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage. - // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor. + // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. Consider moving within SetCursorXXX functions? ImGui::SetCursorPosY(pos_y); ImGuiWindow* window = ImGui::GetCurrentWindow(); - window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; - window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage. + window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + if (window->DC.ColumnsCount > 1) + window->DC.ColumnsCellMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly } // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 From fe7274b6c7ab0039f5ec588d76a4e237dab1be87 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jun 2016 10:25:47 +0200 Subject: [PATCH 245/400] SetCursorScreenPos() fixed not adjusting CursorMaxPos as well --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 3486458b..083dfd62 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5129,6 +5129,7 @@ void ImGui::SetCursorScreenPos(const ImVec2& screen_pos) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos = screen_pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); } float ImGui::GetScrollX() From 5525c2356ab9bfeb3840fa80741f50f6e7013365 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jun 2016 10:30:42 +0200 Subject: [PATCH 246/400] Using GetCurrentWindowRead() instead of GetCurrentWindow() --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 083dfd62..d8ec460e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5082,13 +5082,13 @@ ImVec2 ImGui::GetCursorPos() float ImGui::GetCursorPosX() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; } float ImGui::GetCursorPosY() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; } From 86f42b595028798464cee9b32329b36563e1f357 Mon Sep 17 00:00:00 2001 From: Michael Bartnett Date: Thu, 12 May 2016 00:48:38 -0400 Subject: [PATCH 247/400] osx uses super+arrows for home/end, built on work in ocornut/imgui#473 --- imgui.cpp | 11 +++++++---- imgui.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d8ec460e..51b19cb4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -833,6 +833,7 @@ ImGuiIO::ImGuiIO() #ifdef __APPLE__ WordMovementUsesAltKey = true; // OS X style: Text editing cursor movement using Alt instead of Ctrl ShortcutsUseSuperKey = true; // OS X style: Shortcuts using Cmd/Super instead of Ctrl + HomeEndUsesArrowSuperKey = true; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End DoubleClickSelectsWord = true; // OS X style: Double click selects by word instead of selecting whole text MultiSelectUsesSuperKey = true; // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl #endif @@ -7759,11 +7760,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); const bool is_shortcutkey_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down)); const bool is_wordmove_key_down = (io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl); + const bool is_line_startend_key_down = io.HomeEndUsesArrowSuperKey && is_super_down && !is_ctrl_down && !is_alt_down; + const bool is_text_startend_key_down = is_line_startend_key_down; - if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); } + if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_line_startend_key_down ? STB_TEXTEDIT_K_LINESTART | k_mask : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_line_startend_key_down ? STB_TEXTEDIT_K_LINEEND | k_mask : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_text_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_line_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } diff --git a/imgui.h b/imgui.h index 805aa996..da1682be 100644 --- a/imgui.h +++ b/imgui.h @@ -758,6 +758,7 @@ struct ImGuiIO // Advanced/subtle behaviors bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl + bool HomeEndUsesArrowSuperKey; // = defined(__APPLE__) // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End bool DoubleClickSelectsWord; // = defined(__APPLE__) // OS X style: Double click selects by word instead of selecting whole text bool MultiSelectUsesSuperKey; // = defined(__APPLE__) // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl [unused yet] From 921fc50c85edccd9df29574566277663109ea17e Mon Sep 17 00:00:00 2001 From: Michael Bartnett Date: Thu, 7 Jul 2016 13:03:00 -0400 Subject: [PATCH 248/400] add shortcut+backspace support --- imgui.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 51b19cb4..e31658ad 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7759,6 +7759,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 bool cancel_edit = false; const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); const bool is_shortcutkey_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down)); + const bool is_shortcutkey_and_maybe_shift_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_super_down)); const bool is_wordmove_key_down = (io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl); const bool is_line_startend_key_down = io.HomeEndUsesArrowSuperKey && is_super_down && !is_ctrl_down && !is_alt_down; const bool is_text_startend_key_down = is_line_startend_key_down; @@ -7770,7 +7771,15 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) { if (is_ctrl_down && !edit_state.HasSelection()) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) + { + if (!edit_state.HasSelection()) + { + if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); + else if (io.ShortcutsUseSuperKey && is_shortcutkey_and_maybe_shift_only) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + } + edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); + } else if (IsKeyPressedMap(ImGuiKey_Enter)) { bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; From 9c71ec38f0f79278aefcf785f436a09c97bc3689 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 12 Jul 2016 11:19:38 +0200 Subject: [PATCH 249/400] ImVector: reserve() tweak to avoid undefined behavior warning (#731) --- imgui.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 805aa996..dffb5060 100644 --- a/imgui.h +++ b/imgui.h @@ -885,7 +885,8 @@ public: { if (new_capacity <= Capacity) return; T* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); - memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); + if (Data) + memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); ImGui::MemFree(Data); Data = new_data; Capacity = new_capacity; From d9e2e688e9d0b78f3acbd5ec5ee2eeb7b0671f53 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 13 Jul 2016 01:18:59 +0200 Subject: [PATCH 250/400] InputTextMultiline(): partial fix for when input and internal buffers differs in a way where scrollbar existence differs. (#725) Partial fix, won't stop ids from functioning because of a zombie id. --- imgui.cpp | 10 ++++++++-- imgui_internal.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d8ec460e..6be18795 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1776,6 +1776,12 @@ ImGuiID ImGuiWindow::GetID(const void* ptr) return id; } +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + return ImHash(str, str_end ? (int)(str_end - str) : 0, seed); +} + //----------------------------------------------------------------------------- // Internal API exposed in imgui_internal.h //----------------------------------------------------------------------------- @@ -7633,7 +7639,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 g.MouseCursor = ImGuiMouseCursor_TextInput; } const bool user_clicked = hovered && io.MouseClicked[0]; - const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetID("#SCROLLY"); + const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY"); bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0; if (focus_requested || user_clicked || user_scrolled) @@ -7954,7 +7960,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; ImVec2 text_size(0.f, 0.f); - if (g.ActiveId == id || (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetID("#SCROLLY"))) + if (g.ActiveId == id || (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"))) { edit_state.CursorAnim += g.IO.DeltaTime; diff --git a/imgui_internal.h b/imgui_internal.h index 8cc895f2..4dfa6479 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -657,6 +657,7 @@ public: ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const void* ptr); + ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } From 88721118fdb529a30211ef4e5b789745f367ae68 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 13 Jul 2016 01:54:29 +0200 Subject: [PATCH 251/400] InputTextEx: comments (related to #725) --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6be18795..9e11d860 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7960,7 +7960,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; ImVec2 text_size(0.f, 0.f); - if (g.ActiveId == id || (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"))) + const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY")); + if (g.ActiveId == id || is_currently_scrolling) { edit_state.CursorAnim += g.IO.DeltaTime; @@ -7969,6 +7970,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) // - Measure text height (for scrollbar) // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) + // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. const ImWchar* text_begin = edit_state.Text.Data; ImVec2 cursor_offset, select_start_offset; From c0f77f12ea67dd74f1c90ad4d8633a02cdc589fd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Jul 2016 13:08:37 +0200 Subject: [PATCH 252/400] InputText(): Fixed state corruption/crash bug in stb_textedit redo logic when exhausting undo char buffer (#715 #681) --- stb_textedit.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stb_textedit.h b/stb_textedit.h index 23f0f24e..2dddefe4 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,4 +1,5 @@ // [ImGui] this is a slightly modified version of stb_truetype.h 1.8 +// [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715) // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) // [ImGui] - fixed some minor warnings // [ImGui] - added STB_TEXTEDIT_MOVEWORDLEFT/STB_TEXTEDIT_MOVEWORDRIGHT custom handler (#473) @@ -1101,8 +1102,8 @@ static void stb_textedit_discard_redo(StbUndoState *state) if (state->undo_rec[i].char_storage >= 0) state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 } + STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point-1, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); ++state->redo_point; - STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); } } @@ -1260,6 +1261,7 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) if (r.insert_length) { // easy case: need to insert n characters STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); + s->redo_char_point += r.insert_length; } state->cursor = r.where + r.insert_length; From 81036ee46f3009f2bd09060e6503350a66137804 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Jul 2016 13:27:14 +0200 Subject: [PATCH 253/400] InputTextMultiline(): fix so that IsItemActive() can be used afterwards (otherwise the info was lost by using child/group) --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 9e11d860..ec311154 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8111,6 +8111,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line EndChildFrame(); EndGroup(); + if (g.ActiveId == id || is_currently_scrolling) // Set LastItemId which was lost by EndChild/EndGroup, so user can use IsItemActive() + window->DC.LastItemId = g.ActiveId; } if (is_password) From 04b36bc3978e7760201087db8720ffdc9e99f267 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 14 Jul 2016 13:38:44 +0200 Subject: [PATCH 254/400] TODO list --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index ec311154..8a1aadf3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -490,9 +490,11 @@ - input text: flag to disable live update of the user buffer (also applies to float/int text input) - input text: resize behavior - field could stretch when being edited? hover tooltip shows more text? - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) + - input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725) - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200) - input text multi-line: line numbers? status bar? (follow up on #200) + - input text multi-line: behave better when user changes input buffer while editing is active (even though it is illegal behavior). namely, the change of buffer can create a scrollbar glitch (#725) - input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position. - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) From 44a13a7f25763d4d6419307e47ddfdb4e52b3dc0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 16 Jul 2016 11:29:41 +0200 Subject: [PATCH 255/400] Windows: No default IME handler when compiling using GCC. (#738) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 8a1aadf3..d74e3fed 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9575,7 +9575,7 @@ static void SetClipboardTextFn_DefaultImpl(const char* text) #endif // Win32 API IME support (for Asian languages, etc.) -#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS) +#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS) #include #ifdef _MSC_VER From 4961b2ea18e9446e8a0bd0edb4b3a6942ff8dc89 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 16 Jul 2016 11:44:10 +0200 Subject: [PATCH 256/400] Speculative build fix for FreeBSD+GLIBC configuration See https://github.com/mamedev/mame/commit/a1f9b62dd0a491d6b26291837d43181c0e9e66fa --- imgui_draw.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ba20abc8..1cbd39d8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -18,9 +18,11 @@ #include "imgui_internal.h" #include // vsnprintf, sscanf, printf -#if !defined(alloca) && !defined(__FreeBSD__) && !defined(__DragonFly__) +#if !defined(alloca) #ifdef _WIN32 #include // alloca +#elif (defined(__FreeBSD__) || defined(FreeBSD_kernel) || defined(__DragonFly__)) && !defined(__GLIBC__) +#include // alloca. FreeBSD uses stdlib.h unless GLIBC #else #include // alloca #endif From e2159057658329eb71bf32e3366d1bf4ca1d3545 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 16 Jul 2016 18:12:41 +0200 Subject: [PATCH 257/400] Fixed scrolling offset when using SetScrollY(), SetScrollFromPosY(), SetScrollHere() with menu bar. Tests: a) add SetScrollY(+20) after Begin("ImGui Demo") test with/without title/menu. b) add ImGuiWindowFlags_MenuBar in BeginChild() in scrolling tracking demo. --- imgui.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d74e3fed..296da315 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -131,11 +131,8 @@ ImGui::NewFrame(); // 3) most of your application code here - ImGui::Begin("My window"); - ImGui::Text("Hello, world."); - ImGui::End(); - MyGameUpdate(); // may use ImGui functions - MyGameRender(); // may use ImGui functions + MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); + MyGameRender(); // may use any ImGui functions // 4) render & swap video buffers ImGui::Render(); @@ -4101,7 +4098,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (window->ScrollTarget.y < FLT_MAX) { float center_ratio = window->ScrollTargetCenterRatio.y; - window->Scroll.y = window->ScrollTarget.y - ((1.0f - center_ratio) * window->TitleBarHeight()) - (center_ratio * window->SizeFull.y); + window->Scroll.y = window->ScrollTarget.y - ((1.0f - center_ratio) * (window->TitleBarHeight() + window->MenuBarHeight())) - (center_ratio * window->SizeFull.y); window->ScrollTarget.y = FLT_MAX; } window->Scroll = ImMax(window->Scroll, ImVec2(0.0f, 0.0f)); @@ -5172,7 +5169,7 @@ void ImGui::SetScrollX(float scroll_x) void ImGui::SetScrollY(float scroll_y) { ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTarget.y = scroll_y + window->TitleBarHeight(); // title bar height canceled out when using ScrollTargetRelY + window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY window->ScrollTargetCenterRatio.y = 0.0f; } From 19d02becef94e8e0f1d432a8bd55cd783876583c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 17 Jul 2016 19:17:49 +0200 Subject: [PATCH 258/400] Closing the focused window restore focus to the first active root window in descending z-order (part of #727) --- imgui.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 296da315..14a9fbf0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2250,14 +2250,11 @@ void ImGui::NewFrame() window->SizeFull *= scale; } } - else + else if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) { // Scroll - if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) - { - const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5; - SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines); - } + const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5; + SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines); } } @@ -2275,6 +2272,15 @@ void ImGui::NewFrame() window->Accessed = false; } + // Closing the focused window restore focus to the first active root window in descending z-order + if (g.FocusedWindow && !g.FocusedWindow->WasActive) + for (int i = g.Windows.Size-1; i >= 0; i--) + if (g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow)) + { + FocusWindow(g.Windows[i]); + break; + } + // No window should be open at the beginning of the frame. // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. g.CurrentWindowStack.resize(0); From ffdd7d7f17ee1a2e3ab8fa919e535f54a671bce5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 Jul 2016 15:25:44 +0200 Subject: [PATCH 259/400] Begin: Moved code that calls FocusWindow() on a newly appearing window lower in the function so that Nav branch can use CursorStartPos on the first window frame. (#323) Pushing in master because it _should_ be a no-op but I'd rather test for any issue in Begin() as soon as possible. --- imgui.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 14a9fbf0..19b44536 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3918,16 +3918,10 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us else PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true); - // New windows appears in front if (!window_was_active) { - window->AutoPosLastDirection = -1; - - if (!(flags & ImGuiWindowFlags_NoFocusOnAppearing)) - if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup)) - FocusWindow(window); - // Popup first latch mouse position, will position itself when it appears next frame + window->AutoPosLastDirection = -1; if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) window->PosFloat = g.IO.MousePos; } @@ -4265,6 +4259,11 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (window->AutoFitFramesY > 0) window->AutoFitFramesY--; + // New windows appears in front (we need to do that AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + if (!window_was_active && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) + if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup)) + FocusWindow(window); + // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) { From 4141144b217ce89e819a1c9a4aac165789342188 Mon Sep 17 00:00:00 2001 From: Adisorn Aeksatean Date: Tue, 19 Jul 2016 22:56:59 +0700 Subject: [PATCH 260/400] Added GetGlyphRangesThai() --- imgui.h | 1 + imgui_draw.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/imgui.h b/imgui.h index dffb5060..27518016 100644 --- a/imgui.h +++ b/imgui.h @@ -1322,6 +1322,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters + IMGUI_API const ImWchar* GetGlyphRangesThai(); //Default + Thai charactors // Members // (Access texture data via GetTexData*() calls which will setup a default font for you.) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1cbd39d8..c5770da8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1652,6 +1652,17 @@ const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() return &ranges[0]; } +const ImWchar* ImFontAtlas::GetGlyphRangesThai() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, //Basic Latin + 0x0E00, 0x0E7F, //Thai Unicode + 0, + }; + return &ranges[0]; +} + //----------------------------------------------------------------------------- // ImFont //----------------------------------------------------------------------------- From 8efd05a1489a92f2c4d33ef7a0e2a3f3702c191f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 20 Jul 2016 11:39:38 +0200 Subject: [PATCH 261/400] Tab->Spaces, missing spaces, typos --- imgui.h | 2 +- imgui_draw.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index 27518016..fbd8c9fe 100644 --- a/imgui.h +++ b/imgui.h @@ -1322,7 +1322,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters - IMGUI_API const ImWchar* GetGlyphRangesThai(); //Default + Thai charactors + IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters // Members // (Access texture data via GetTexData*() calls which will setup a default font for you.) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c5770da8..45549298 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1654,13 +1654,13 @@ const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() const ImWchar* ImFontAtlas::GetGlyphRangesThai() { - static const ImWchar ranges[] = - { - 0x0020, 0x00FF, //Basic Latin - 0x0E00, 0x0E7F, //Thai Unicode - 0, - }; - return &ranges[0]; + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x0E00, 0x0E7F, // Thai + 0, + }; + return &ranges[0]; } //----------------------------------------------------------------------------- From d8dacd729bfae825a8a820e02d6e82d39fa5005c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Jul 2016 10:10:41 +0200 Subject: [PATCH 262/400] Examples: SDL+OpenGL: explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it (#752) --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 1 + examples/sdl_opengl_example/imgui_impl_sdl.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index d97b4cc0..e0193862 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -186,6 +186,7 @@ void ImGui_ImplSdlGL3_CreateFontsTexture() glBindTexture(GL_TEXTURE_2D, g_FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index ae42f143..434a7c22 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -165,6 +165,7 @@ bool ImGui_ImplSdl_CreateDeviceObjects() glBindTexture(GL_TEXTURE_2D, g_FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); // Store our identifier From e5b6ddde2683621c6f063d9814fd8f0780f1a6c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Jul 2016 10:42:08 +0200 Subject: [PATCH 263/400] InputText(): minor tidying up/simplification following changes for osx style improvements (#650) --- imgui.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5aea9601..ececb106 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7768,16 +7768,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Handle various key-presses bool cancel_edit = false; const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); - const bool is_shortcutkey_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down)); - const bool is_shortcutkey_and_maybe_shift_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_super_down)); - const bool is_wordmove_key_down = (io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl); - const bool is_line_startend_key_down = io.HomeEndUsesArrowSuperKey && is_super_down && !is_ctrl_down && !is_alt_down; - const bool is_text_startend_key_down = is_line_startend_key_down; + const bool is_shortcutkey_only = io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down); + const bool is_wordmove_key_down = io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl; + const bool is_startend_key_down = io.HomeEndUsesArrowSuperKey && is_super_down && !is_ctrl_down && !is_alt_down; - if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_line_startend_key_down ? STB_TEXTEDIT_K_LINESTART | k_mask : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_line_startend_key_down ? STB_TEXTEDIT_K_LINEEND | k_mask : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_text_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_line_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } @@ -7786,7 +7784,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (!edit_state.HasSelection()) { if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); - else if (io.ShortcutsUseSuperKey && is_shortcutkey_and_maybe_shift_only) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + else if (io.ShortcutsUseSuperKey && is_super_down && !is_alt_down && !is_ctrl_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); } edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } From 0ff22dbf0bea35975f52f0578265c5b7eb7a9e41 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Jul 2016 10:51:35 +0200 Subject: [PATCH 264/400] InputTextEx(): minor tidying up --- imgui.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ececb106..3d5f690b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7717,8 +7717,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 g.ActiveIdAllowOverlap = !io.MouseDown[0]; // Edit in progress - const float mouse_x = (g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; - const float mouse_y = (is_multiline ? (g.IO.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); if (select_all || (hovered && !io.DoubleClickSelectsWord && io.MouseDoubleClicked[0])) { @@ -7745,14 +7745,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) edit_state.SelectedAllMouseLock = false; - if (g.IO.InputCharacters[0]) + if (io.InputCharacters[0]) { // Process text input (before we check for Return because using some IME will effectively send a Return?) // We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters. if (!(is_ctrl_down && !is_alt_down) && is_editable) { - for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++) - if (unsigned int c = (unsigned int)g.IO.InputCharacters[n]) + for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++) + if (unsigned int c = (unsigned int)io.InputCharacters[n]) { // Insert character if they pass filtering if (!InputTextFilterCharacter(&c, flags, callback, user_data)) @@ -7820,13 +7820,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (cut && !edit_state.HasSelection()) edit_state.SelectAll(); - if (g.IO.SetClipboardTextFn) + if (io.SetClipboardTextFn) { const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0; const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW; edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1); ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie); - g.IO.SetClipboardTextFn(edit_state.TempTextBuffer.Data); + io.SetClipboardTextFn(edit_state.TempTextBuffer.Data); } if (cut) @@ -7838,9 +7838,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) { // Paste - if (g.IO.GetClipboardTextFn) + if (io.GetClipboardTextFn) { - if (const char* clipboard = g.IO.GetClipboardTextFn()) + if (const char* clipboard = io.GetClipboardTextFn()) { // Remove new-line from pasted buffer const int clipboard_len = (int)strlen(clipboard); @@ -7977,7 +7977,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY")); if (g.ActiveId == id || is_currently_scrolling) { - edit_state.CursorAnim += g.IO.DeltaTime; + edit_state.CursorAnim += io.DeltaTime; // This is going to be messy. We need to: // - Display the text (this alone can be more easily clipped) From 666d83b5c78b7b4166298a7a6426cc0367f1d5fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Jul 2016 10:56:47 +0200 Subject: [PATCH 265/400] InputText/IO: Got rid of individual OSX options in ImGuiIO, added io.OSXBehaviors (#473, #650) --- imgui.cpp | 19 ++++++++----------- imgui.h | 6 +----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3d5f690b..7f54786c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -830,11 +830,7 @@ ImGuiIO::ImGuiIO() // Set OS X style defaults based on __APPLE__ compile time flag #ifdef __APPLE__ - WordMovementUsesAltKey = true; // OS X style: Text editing cursor movement using Alt instead of Ctrl - ShortcutsUseSuperKey = true; // OS X style: Shortcuts using Cmd/Super instead of Ctrl - HomeEndUsesArrowSuperKey = true; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End - DoubleClickSelectsWord = true; // OS X style: Double click selects by word instead of selecting whole text - MultiSelectUsesSuperKey = true; // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl + OSXBehaviors = true; #endif } @@ -7720,12 +7716,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); - if (select_all || (hovered && !io.DoubleClickSelectsWord && io.MouseDoubleClicked[0])) + const bool osx_double_click_selects_words = io.OSXBehaviors; // OS X style: Double click selects by word instead of selecting whole text + if (select_all || (hovered && !osx_double_click_selects_words && io.MouseDoubleClicked[0])) { edit_state.SelectAll(); edit_state.SelectedAllMouseLock = true; } - else if (hovered && io.DoubleClickSelectsWord && io.MouseDoubleClicked[0]) + else if (hovered && osx_double_click_selects_words && io.MouseDoubleClicked[0]) { // Select a word only, OS X style (by simulating keystrokes) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); @@ -7768,9 +7765,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Handle various key-presses bool cancel_edit = false; const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); - const bool is_shortcutkey_only = io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down); - const bool is_wordmove_key_down = io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl; - const bool is_startend_key_down = io.HomeEndUsesArrowSuperKey && is_super_down && !is_ctrl_down && !is_alt_down; + const bool is_shortcutkey_only = (io.OSXBehaviors ? (is_super_down && !is_ctrl_down) : (is_ctrl_down && !is_super_down)) && !is_alt_down && !is_shift_down; // OS X style: Shortcuts using Cmd/Super instead of Ctrl + const bool is_wordmove_key_down = io.OSXBehaviors ? is_alt_down : is_ctrl_down; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = io.OSXBehaviors && is_super_down && !is_ctrl_down && !is_alt_down; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } @@ -7784,7 +7781,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (!edit_state.HasSelection()) { if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); - else if (io.ShortcutsUseSuperKey && is_super_down && !is_alt_down && !is_ctrl_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + else if (io.OSXBehaviors && is_super_down && !is_alt_down && !is_ctrl_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); } edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } diff --git a/imgui.h b/imgui.h index 66155067..db5fd843 100644 --- a/imgui.h +++ b/imgui.h @@ -756,11 +756,7 @@ struct ImGuiIO ImVec2 DisplayVisibleMax; // (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize // Advanced/subtle behaviors - bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl - bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl - bool HomeEndUsesArrowSuperKey; // = defined(__APPLE__) // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End - bool DoubleClickSelectsWord; // = defined(__APPLE__) // OS X style: Double click selects by word instead of selecting whole text - bool MultiSelectUsesSuperKey; // = defined(__APPLE__) // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl [unused yet] + bool OSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl //------------------------------------------------------------------ // User Functions From 776ea6b946d7c19f42e0de22a1052c178baaaa73 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Jul 2016 11:01:06 +0200 Subject: [PATCH 266/400] InputTextEx(): more shallow tidying up, still being cautious with this function --- imgui.cpp | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7f54786c..d278a708 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7771,8 +7771,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } @@ -7835,32 +7835,29 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) { // Paste - if (io.GetClipboardTextFn) + if (const char* clipboard = io.GetClipboardTextFn ? io.GetClipboardTextFn() : NULL) { - if (const char* clipboard = io.GetClipboardTextFn()) + // Remove new-line from pasted buffer + const int clipboard_len = (int)strlen(clipboard); + ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar)); + int clipboard_filtered_len = 0; + for (const char* s = clipboard; *s; ) { - // Remove new-line from pasted buffer - const int clipboard_len = (int)strlen(clipboard); - ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar)); - int clipboard_filtered_len = 0; - for (const char* s = clipboard; *s; ) - { - unsigned int c; - s += ImTextCharFromUtf8(&c, s, NULL); - if (c == 0) - break; - if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data)) - continue; - clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; - } - clipboard_filtered[clipboard_filtered_len] = 0; - if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation - { - stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len); - edit_state.CursorFollow = true; - } - ImGui::MemFree(clipboard_filtered); + unsigned int c; + s += ImTextCharFromUtf8(&c, s, NULL); + if (c == 0) + break; + if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data)) + continue; + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; } + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation + { + stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len); + edit_state.CursorFollow = true; + } + ImGui::MemFree(clipboard_filtered); } } From 7086a1785423bf6f5abae6a63b792d21daffdeeb Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Jul 2016 11:06:16 +0200 Subject: [PATCH 267/400] InputTextEx: got rid of unnecessary locals. --- imgui.cpp | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d278a708..1590f377 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7625,10 +7625,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // NB: we are only allowed to access 'edit_state' if we are the active widget. ImGuiTextEditState& edit_state = g.InputTextState; - const bool is_ctrl_down = io.KeyCtrl; - const bool is_shift_down = io.KeyShift; - const bool is_alt_down = io.KeyAlt; - const bool is_super_down = io.KeySuper; const bool focus_requested = FocusableItemRegister(window, g.ActiveId == id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent); const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; @@ -7678,7 +7674,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 } if (flags & ImGuiInputTextFlags_AlwaysInsertMode) edit_state.StbState.insert_mode = true; - if (!is_multiline && (focus_requested_by_tab || (user_clicked && is_ctrl_down))) + if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) select_all = true; } SetActiveID(id, window); @@ -7746,7 +7742,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 { // Process text input (before we check for Return because using some IME will effectively send a Return?) // We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters. - if (!(is_ctrl_down && !is_alt_down) && is_editable) + if (!(io.KeyCtrl && !io.KeyAlt) && is_editable) { for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++) if (unsigned int c = (unsigned int)io.InputCharacters[n]) @@ -7764,31 +7760,31 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Handle various key-presses bool cancel_edit = false; - const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); - const bool is_shortcutkey_only = (io.OSXBehaviors ? (is_super_down && !is_ctrl_down) : (is_ctrl_down && !is_super_down)) && !is_alt_down && !is_shift_down; // OS X style: Shortcuts using Cmd/Super instead of Ctrl - const bool is_wordmove_key_down = io.OSXBehaviors ? is_alt_down : is_ctrl_down; // OS X style: Text editing cursor movement using Alt instead of Ctrl - const bool is_startend_key_down = io.OSXBehaviors && is_super_down && !is_ctrl_down && !is_alt_down; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); + const bool is_shortcut_key_only = (io.OSXBehaviors ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl + const bool is_wordmove_key_down = io.OSXBehaviors ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = io.OSXBehaviors && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (is_ctrl_down) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) { if (!edit_state.HasSelection()) { if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); - else if (io.OSXBehaviors && is_super_down && !is_alt_down && !is_ctrl_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + else if (io.OSXBehaviors && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); } edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Enter)) { bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; - if (!is_multiline || (ctrl_enter_for_new_line && !is_ctrl_down) || (!ctrl_enter_for_new_line && is_ctrl_down)) + if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) { SetActiveID(0); enter_pressed = true; @@ -7800,17 +7796,17 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 edit_state.OnKeyPressed((int)c); } } - else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !is_ctrl_down && !is_shift_down && !is_alt_down && is_editable) + else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable) { unsigned int c = '\t'; // Insert TAB if (InputTextFilterCharacter(&c, flags, callback, user_data)) edit_state.OnKeyPressed((int)c); } else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; } - else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } - else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } - else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } - else if (is_shortcutkey_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) + else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } + else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } + else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } + else if (is_shortcut_key_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) { // Cut, Copy const bool cut = IsKeyPressedMap(ImGuiKey_X); @@ -7832,12 +7828,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 stb_textedit_cut(&edit_state, &edit_state.StbState); } } - else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) + else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) { // Paste if (const char* clipboard = io.GetClipboardTextFn ? io.GetClipboardTextFn() : NULL) { - // Remove new-line from pasted buffer + // Filter pasted buffer const int clipboard_len = (int)strlen(clipboard); ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar)); int clipboard_filtered_len = 0; From cabba0f15882317a5bf891b92e596b32761a13ca Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 29 Jul 2016 18:52:38 +0200 Subject: [PATCH 268/400] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8a9eab15..ea0d4639 100644 --- a/README.md +++ b/README.md @@ -168,13 +168,14 @@ Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Bin Ongoing ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). Double-chocolate sponsors: -- Media Molecule, Mobigame +- Media Molecule +- Mobigame Salty caramel supporters: -- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima +- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko. Caramel supporters: -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley. +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society. And other supporters; thanks! From 954c890c6782fda494a3ac36f3c5a591db584cf4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 30 Jul 2016 23:41:44 +0200 Subject: [PATCH 269/400] SameLine() with explicit X position is relative to left of group/columns (ref #746, #125, #630) --- imgui.cpp | 12 ++++++++---- imgui_internal.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1590f377..5a55b41a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -150,6 +150,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. @@ -4221,6 +4222,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Setup drawing context window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffsetX = 0.0f; window->DC.ColumnsOffsetX = 0.0f; window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y); window->DC.CursorPos = window->DC.CursorStartPos; @@ -9116,7 +9118,8 @@ void ImGui::BeginGroup() group_data.BackupLogLinePosY = window->DC.LogLinePosY; group_data.AdvanceCursor = true; - window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; + 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; @@ -9140,6 +9143,7 @@ void ImGui::EndGroup() window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; window->DC.IndentX = group_data.BackupIndentX; + window->DC.GroupOffsetX = window->DC.IndentX; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; if (group_data.AdvanceCursor) @@ -9156,7 +9160,7 @@ void ImGui::EndGroup() // Gets back to previous line and continue with horizontal layout // pos_x == 0 : follow right after previous item -// pos_x != 0 : align to specified x position +// pos_x != 0 : align to specified x position (relative to window/group left) // spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 // spacing_w >= 0 : enforce spacing amount void ImGui::SameLine(float pos_x, float spacing_w) @@ -9169,7 +9173,7 @@ void ImGui::SameLine(float pos_x, float spacing_w) if (pos_x != 0.0f) { if (spacing_w < 0.0f) spacing_w = 0.0f; - window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX; window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } else @@ -9352,7 +9356,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) if (held) { if (g.ActiveIdIsJustActivated) - g.ActiveIdClickOffset.x -= 4; // Store from center of column line + g.ActiveIdClickOffset.x -= 4; // Store from center of column line (we used a 8 wide rect for columns clicking) x = GetDraggedColumnOffset(i); SetColumnOffset(i, x); } diff --git a/imgui_internal.h b/imgui_internal.h index 4dfa6479..7b59bb63 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -546,6 +546,7 @@ struct IMGUI_API ImGuiDrawContext int StackSizesBackup[6]; // Store size of various stacks for asserting float IndentX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) + float GroupOffsetX; float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. int ColumnsCurrent; int ColumnsCount; From 0a1d456de1dececa7c18f213cea11e94fbe17c6f Mon Sep 17 00:00:00 2001 From: Jamie Seward Date: Sat, 30 Jul 2016 15:26:49 -0700 Subject: [PATCH 270/400] Fix compile warnings in SDL examples --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 1 - examples/sdl_opengl_example/imgui_impl_sdl.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index e0193862..7011875a 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -152,7 +152,6 @@ bool ImGui_ImplSdlGL3_ProcessEvent(SDL_Event* event) } case SDL_TEXTINPUT: { - ImGuiIO& io = ImGui::GetIO(); io.AddInputCharactersUTF8(event->text.text); return true; } diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl_example/imgui_impl_sdl.cpp index 434a7c22..63ed9f44 100644 --- a/examples/sdl_opengl_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl_example/imgui_impl_sdl.cpp @@ -131,7 +131,6 @@ bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event) } case SDL_TEXTINPUT: { - ImGuiIO& io = ImGui::GetIO(); io.AddInputCharactersUTF8(event->text.text); return true; } From 907265d6320ffdfb438fff94aa88133d33ac3775 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 31 Jul 2016 16:48:06 +0200 Subject: [PATCH 271/400] Using ImGuiID instead of ImU32 is a few places --- imgui.cpp | 17 ++++++++--------- imgui.h | 6 +++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5a55b41a..de569db5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -999,7 +999,6 @@ ImU32 ImHash(const void* data, int data_size, ImU32 seed) // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller. if (c == '#' && current[0] == '#' && current[1] == '#') crc = seed; - crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; } } @@ -1302,7 +1301,7 @@ void ImGuiStorage::Clear() } // std::lower_bound but without the bullshit -static ImVector::iterator LowerBound(ImVector& data, ImU32 key) +static ImVector::iterator LowerBound(ImVector& data, ImGuiID key) { ImVector::iterator first = data.begin(); ImVector::iterator last = data.end(); @@ -1324,7 +1323,7 @@ static ImVector::iterator LowerBound(ImVector::iterator it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) @@ -1332,12 +1331,12 @@ int ImGuiStorage::GetInt(ImU32 key, int default_val) const return it->val_i; } -bool ImGuiStorage::GetBool(ImU32 key, bool default_val) const +bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const { return GetInt(key, default_val ? 1 : 0) != 0; } -float ImGuiStorage::GetFloat(ImU32 key, float default_val) const +float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const { ImVector::iterator it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) @@ -1384,7 +1383,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) } // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) -void ImGuiStorage::SetInt(ImU32 key, int val) +void ImGuiStorage::SetInt(ImGuiID key, int val) { ImVector::iterator it = LowerBound(Data, key); if (it == Data.end() || it->key != key) @@ -1395,12 +1394,12 @@ void ImGuiStorage::SetInt(ImU32 key, int val) it->val_i = val; } -void ImGuiStorage::SetBool(ImU32 key, bool val) +void ImGuiStorage::SetBool(ImGuiID key, bool val) { SetInt(key, val ? 1 : 0); } -void ImGuiStorage::SetFloat(ImU32 key, float val) +void ImGuiStorage::SetFloat(ImGuiID key, float val) { ImVector::iterator it = LowerBound(Data, key); if (it == Data.end() || it->key != key) @@ -1411,7 +1410,7 @@ void ImGuiStorage::SetFloat(ImU32 key, float val) it->val_f = val; } -void ImGuiStorage::SetVoidPtr(ImU32 key, void* val) +void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) { ImVector::iterator it = LowerBound(Data, key); if (it == Data.end() || it->key != key) diff --git a/imgui.h b/imgui.h index db5fd843..67f46c61 100644 --- a/imgui.h +++ b/imgui.h @@ -62,11 +62,11 @@ struct ImGuiSizeConstraintCallbackData;// Structure used to constraint window si struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiContext; // ImGui context (opaque) -// Enumerations (declared as int for compatibility and to not pollute the top of this file) -typedef unsigned int ImU32; +// Typedefs and Enumerations (declared as int for compatibility and to not pollute the top of this file) +typedef unsigned int ImU32; // 32-bit unsigned integer (typically used to store packed colors) +typedef unsigned int ImGuiID; // unique ID used by widgets (typically hashed from a stack of string) typedef unsigned short ImWchar; // character for keyboard input/display typedef void* ImTextureID; // user data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) -typedef ImU32 ImGuiID; // unique ID used by widgets (typically hashed from a stack of string) typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_ typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_ typedef int ImGuiKey; // a key identifier (ImGui-side enum) // enum ImGuiKey_ From 7588dfb67e7dd8970b64bffc87c2659fe7684ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cicho=C5=84?= Date: Fri, 5 Aug 2016 11:47:16 +0200 Subject: [PATCH 272/400] Add ability to test arbitrary rectangle for visibility without need of moving cursor. --- imgui.cpp | 6 ++++++ imgui.h | 1 + 2 files changed, 7 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index de569db5..7332d27c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9102,6 +9102,12 @@ bool ImGui::IsRectVisible(const ImVec2& size) return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } +bool ImGui::IsRectVisible(const ImVec2& a, const ImVec2& b) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ClipRect.Overlaps(ImRect(a, b)); +} + // 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() { diff --git a/imgui.h b/imgui.h index 67f46c61..40be5091 100644 --- a/imgui.h +++ b/imgui.h @@ -410,6 +410,7 @@ namespace ImGui IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused IMGUI_API bool IsRootWindowOrAnyChildHovered(); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup) IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle of given size starting from cursor pos is visible (not clipped). to perform coarse clipping on user's side (as an optimization) + IMGUI_API bool IsRectVisible(const ImVec2& a, const ImVec2& b); // " IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); From a7f6ea592fe38e7ea7896d48afbc37587bfa2360 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 6 Aug 2016 09:22:41 +0200 Subject: [PATCH 273/400] Moved GetColorU32 out of imgui_internal.h to avoid inlining mess (#759) --- imgui.cpp | 14 ++++++++++++++ imgui_internal.h | 3 --- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index de569db5..6005fb26 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1197,6 +1197,20 @@ ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) return out; } +ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) +{ + ImVec4 c = GImGui->Style.Colors[idx]; + c.w *= GImGui->Style.Alpha * alpha_mul; + return ImGui::ColorConvertFloat4ToU32(c); +} + +ImU32 ImGui::GetColorU32(const ImVec4& col) +{ + ImVec4 c = col; + c.w *= GImGui->Style.Alpha; + return ImGui::ColorConvertFloat4ToU32(c); +} + // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) diff --git a/imgui_internal.h b/imgui_internal.h index 7b59bb63..dc02f719 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -703,9 +703,6 @@ namespace ImGui IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); - inline IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul) { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * alpha_mul; return ImGui::ColorConvertFloat4ToU32(c); } - inline IMGUI_API ImU32 GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } - // NB: All position are in absolute pixels coordinates (not window coordinates) // FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp! // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. From af33efb1460218bb649392853f556ed218b2dcb3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 6 Aug 2016 09:35:05 +0200 Subject: [PATCH 274/400] Using IM_COL32() for colors in a few spots (#767) --- imgui.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6005fb26..29edee02 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1850,7 +1850,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y) window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); - //window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, 0xFF0000FF, 4); // Debug + //window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // Debug window->DC.PrevLineHeight = line_height; window->DC.PrevLineTextBaseOffset = text_base_offset; @@ -2702,10 +2702,10 @@ void ImGui::Render() const ImVec2 size = cursor_data.Size; const ImTextureID tex_id = g.IO.Fonts->TexID; g.OverlayDrawList.PushTextureID(tex_id); - g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow - g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow - g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFF000000); // Black border - g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFFFFFFFF); // White fill + g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow + g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow + g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,255)); // Black border + g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], IM_COL32(255,255,255,255)); // White fill g.OverlayDrawList.PopTextureID(); } if (!g.OverlayDrawList.VtxBuffer.empty()) From b8397c293379a890811f3fba8ce84ef680f83423 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 6 Aug 2016 09:40:26 +0200 Subject: [PATCH 275/400] Tweak comments (#768) --- imgui.cpp | 4 ++-- imgui.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e091382e..81a57d96 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9116,10 +9116,10 @@ bool ImGui::IsRectVisible(const ImVec2& size) return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } -bool ImGui::IsRectVisible(const ImVec2& a, const ImVec2& b) +bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) { ImGuiWindow* window = GetCurrentWindowRead(); - return window->ClipRect.Overlaps(ImRect(a, b)); + return window->ClipRect.Overlaps(ImRect(rect_min, 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.) diff --git a/imgui.h b/imgui.h index 40be5091..60a15af2 100644 --- a/imgui.h +++ b/imgui.h @@ -409,8 +409,8 @@ namespace ImGui IMGUI_API bool IsRootWindowFocused(); // is current root window focused (root = top-most parent of a child, otherwise self) IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused IMGUI_API bool IsRootWindowOrAnyChildHovered(); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup) - IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle of given size starting from cursor pos is visible (not clipped). to perform coarse clipping on user's side (as an optimization) - IMGUI_API bool IsRectVisible(const ImVec2& a, const ImVec2& b); // " + IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. + IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); From 5d1a0a6f77955b7b7bff926269fb71915ab48415 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 6 Aug 2016 09:48:04 +0200 Subject: [PATCH 276/400] Removed a handful of obsolete (trivial) function redirection from 1.34 and 1.38 (march-april 2015) OpenNextNode() -> SetNextTreeNodeOpen() GetWindowIsFocused() -> IsWindowFocused() GetItemBoxMin() -> GetItemRectMin() GetItemBoxMax() -> GetItemRectMax() IsMouseHoveringBox() -> IsMouseHoveringRect() IsClipped() -> !IsRectVisible() --- imgui.cpp | 8 ++++---- imgui.h | 10 ++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 81a57d96..90227eb1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -209,15 +209,15 @@ - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). - - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete). + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. - - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete). + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing - - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete). + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) - - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function (will obsolete). + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior diff --git a/imgui.h b/imgui.h index 60a15af2..b85eaeff 100644 --- a/imgui.h +++ b/imgui.h @@ -468,15 +468,9 @@ namespace ImGui static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ - static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpen(open, 0); } // OBSOLETE 1.34+ - static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+ - static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+ - static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE 1.36+ - static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE 1.36+ - static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.38+ - static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+ - static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE 1.36+ static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETE 1.42+ + static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+ + static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+ #endif } // namespace ImGui From 6eb35b8a0495e7f3fe537a39e59903e5fb45e022 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 7 Aug 2016 13:53:41 +0200 Subject: [PATCH 277/400] BulletText(): doesn't stop displaying at the ## mark --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 90227eb1..8fba82b5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6180,7 +6180,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) const char* text_begin = g.TempBuffer; const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - const ImVec2 label_size = CalcTextSize(text_begin, text_end, true); + const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding @@ -6190,7 +6190,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // Render RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); - RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end); + RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false); } void ImGui::BulletText(const char* fmt, ...) From 4bc3f9d1f72dccdb40836d4bb798af3d1a7bd00f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 11 Aug 2016 22:59:44 +0200 Subject: [PATCH 278/400] Minor shuffle to ease merging branches. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 8fba82b5..6d726642 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4253,9 +4253,9 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->DC.AllowKeyboardFocus = true; window->DC.ButtonRepeat = false; window->DC.ItemWidthStack.resize(0); - window->DC.TextWrapPosStack.resize(0); window->DC.AllowKeyboardFocusStack.resize(0); window->DC.ButtonRepeatStack.resize(0); + window->DC.TextWrapPosStack.resize(0); window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect; window->DC.ColumnsCurrent = 0; window->DC.ColumnsCount = 1; From 0f9addb002bf2c79b5e087449a764673c040c35e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 7 Aug 2016 20:05:24 +0200 Subject: [PATCH 279/400] Minor shuffle to ease merging branches. (tentative. fugly but those fields will be removed anyway) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6d726642..cb334f15 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4256,7 +4256,6 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->DC.AllowKeyboardFocusStack.resize(0); window->DC.ButtonRepeatStack.resize(0); window->DC.TextWrapPosStack.resize(0); - window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect; window->DC.ColumnsCurrent = 0; window->DC.ColumnsCount = 1; window->DC.ColumnsStartPosY = window->DC.CursorPos.y; @@ -4264,6 +4263,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->DC.TreeDepth = 0; window->DC.StateStorage = &window->StateStorage; window->DC.GroupStack.resize(0); + window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect; window->MenuColumns.Update(3, style.ItemSpacing.x, !window_was_active); if (window->AutoFitFramesX > 0) From 4f389b7f6ab54a884730b09050d76a9964bee812 Mon Sep 17 00:00:00 2001 From: Max Thrun Date: Thu, 18 Aug 2016 11:00:23 -0700 Subject: [PATCH 280/400] Add null terminator to ShowStyleEditor output_type combo options Without a null terminator the Combo() function indexes outside of the "items_separated_by_zeros" string. --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 67846e7a..0d9dbbcf 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1670,7 +1670,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) } ImGui::LogFinish(); } - ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY"); ImGui::PopItemWidth(); + ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); ImGui::SameLine(); ImGui::Checkbox("Only Modified Fields", &output_only_modified); static ImGuiColorEditMode edit_mode = ImGuiColorEditMode_RGB; From 3234f81cb17a2dc0b8d63bf4ae8a610f93f9a1ce Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Sat, 20 Aug 2016 13:08:34 +0200 Subject: [PATCH 281/400] maxImageCount may be 0; add missing sType; change to 1 push constant range --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 12 +++++------- examples/vulkan_example/main.cpp | 9 ++++++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 33d8e997..fa17959f 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -661,19 +661,16 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() if (!g_PipelineLayout) { - VkPushConstantRange push_constants[2] = {}; + VkPushConstantRange push_constants[1] = {}; push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].offset = sizeof(float) * 0; - push_constants[0].size = sizeof(float) * 2; - push_constants[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - push_constants[1].offset = sizeof(float) * 2; - push_constants[1].size = sizeof(float) * 2; + push_constants[0].size = sizeof(float) * 4; VkDescriptorSetLayout set_layout[1] = {g_DescriptorSetLayout}; VkPipelineLayoutCreateInfo layout_info = {}; layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layout_info.setLayoutCount = 1; layout_info.pSetLayouts = set_layout; - layout_info.pushConstantRangeCount = 2; + layout_info.pushConstantRangeCount = 1; layout_info.pPushConstantRanges = push_constants; err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout); ImGui_ImplGlfwVulkan_VkResult(err); @@ -750,7 +747,8 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = {}; - dynamic_state.dynamicStateCount = 2; + dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state.dynamicStateCount = 2; dynamic_state.pDynamicStates = dynamic_states; VkGraphicsPipelineCreateInfo info = {}; diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 130fd870..040ff241 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -88,7 +88,14 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkSurfaceCapabilitiesKHR cap; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_Gpu, g_Surface, &cap); check_vk_result(err); - info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; + if (cap.maxImageCount > 0) + { + info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; + } + else + { + info.minImageCount = cap.minImageCount + 2; + } if (cap.currentExtent.width == 0xffffffff) { fb_width = w; From 4bc6a951fe11d34c0e64af08d1802aef011f2215 Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Sat, 20 Aug 2016 13:27:03 +0200 Subject: [PATCH 282/400] tabs to space, remove braces --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 4 ++-- examples/vulkan_example/main.cpp | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index fa17959f..a9c18f33 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -747,8 +747,8 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = {}; - dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state.dynamicStateCount = 2; + dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state.dynamicStateCount = 2; dynamic_state.pDynamicStates = dynamic_states; VkGraphicsPipelineCreateInfo info = {}; diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 040ff241..f3318fed 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -88,14 +88,10 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkSurfaceCapabilitiesKHR cap; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_Gpu, g_Surface, &cap); check_vk_result(err); - if (cap.maxImageCount > 0) - { - info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; - } - else - { - info.minImageCount = cap.minImageCount + 2; - } + if (cap.maxImageCount > 0) + info.minImageCount = (cap.minImageCount + 2 < cap.maxImageCount) ? (cap.minImageCount + 2) : cap.maxImageCount; + else + info.minImageCount = cap.minImageCount + 2; if (cap.currentExtent.width == 0xffffffff) { fb_width = w; From 82768e05f3e6b0b85b0d45253c7017692cb86833 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 20 Aug 2016 13:30:42 +0200 Subject: [PATCH 283/400] Ignore list for Visual Studio --- examples/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/.gitignore b/examples/.gitignore index 8157afff..41704453 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -33,6 +33,7 @@ opengl3_example/opengl3_example *.obj *.exe *.pdb +*.ilk ## Ini files imgui.ini From 63d47bc5a4b26d21549a640ce6af4b5b40022d26 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Aug 2016 16:55:06 +0200 Subject: [PATCH 284/400] ImFormatString() Fixed an overflow handling bug with implementation of vsnprintf() that do not return -1 (#793) --- imgui.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cb334f15..a8cddc64 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -944,21 +944,30 @@ const char* ImStristr(const char* haystack, const char* haystack_end, const char return NULL; } + +// MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). +// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. int ImFormatString(char* buf, int buf_size, const char* fmt, ...) { + IM_ASSERT(buf_size > 0); va_list args; va_start(args, fmt); int w = vsnprintf(buf, buf_size, fmt, args); va_end(args); - buf[buf_size-1] = 0; - return (w == -1) ? buf_size : w; + if (w == -1 || w >= buf_size) + w = buf_size - 1; + buf[w] = 0; + return w; } int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args) { + IM_ASSERT(buf_size > 0); int w = vsnprintf(buf, buf_size, fmt, args); - buf[buf_size-1] = 0; - return (w == -1) ? buf_size : w; + if (w == -1 || w >= buf_size) + w = buf_size - 1; + buf[w] = 0; + return w; } // Pass data_size==0 for zero-terminated strings From 3c384c2f105a787cc0aebeca0bd1af073d9ffa4e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Aug 2016 10:18:09 +0200 Subject: [PATCH 285/400] Examples: Renaming opengl_example/ to opengl2_example/ for clarity (1/2 because git) --- examples/README.txt | 23 ++++++++++--------- examples/imgui_examples_msvc2010.sln | 2 +- .../Makefile | 2 +- .../build_win32.bat | 0 .../imgui_impl_glfw.cpp | 0 .../imgui_impl_glfw.h | 0 .../main.cpp | 0 .../opengl_example.vcxproj | 0 .../opengl_example.vcxproj.filters | 0 .../README.md | 0 .../imgui_impl_sdl.cpp | 0 .../imgui_impl_sdl.h | 0 .../main.cpp | 0 imgui.cpp | 2 +- 14 files changed, 15 insertions(+), 14 deletions(-) rename examples/{opengl_example => opengl2_example}/Makefile (98%) rename examples/{opengl_example => opengl2_example}/build_win32.bat (100%) rename examples/{opengl_example => opengl2_example}/imgui_impl_glfw.cpp (100%) rename examples/{opengl_example => opengl2_example}/imgui_impl_glfw.h (100%) rename examples/{opengl_example => opengl2_example}/main.cpp (100%) rename examples/{opengl_example => opengl2_example}/opengl_example.vcxproj (100%) rename examples/{opengl_example => opengl2_example}/opengl_example.vcxproj.filters (100%) rename examples/{sdl_opengl_example => sdl_opengl2_example}/README.md (100%) rename examples/{sdl_opengl_example => sdl_opengl2_example}/imgui_impl_sdl.cpp (100%) rename examples/{sdl_opengl_example => sdl_opengl2_example}/imgui_impl_sdl.h (100%) rename examples/{sdl_opengl_example => sdl_opengl2_example}/main.cpp (100%) diff --git a/examples/README.txt b/examples/README.txt index df2e86da..5a1c8df4 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -8,11 +8,13 @@ Third party languages and frameworks bindings: https://github.com/ocornut/imgui/ TL;DR; - Newcomers, read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup ImGui in your codebase. - - Refer to 'opengl_example' to understand how the library is setup, it is the simplest one. + - Refer to 'opengl2_example' to LEARN how the library is setup, it is the simplest one. The other examples requires more boilerplate and are harder to read. + - If you are using OpenGL in your application, probably use an opengl3_xxx backend. + Mixing old fixed pipeline OpenGL2 and programmable pipeline OpenGL3+ isn't well supported by drivers. - If you are using of the backend provided here, so you can copy the imgui_impl_xxx.cpp/h files to your project and use them unmodified. - - If you have your own engine, you probably want to start from 'opengl_example' and adapt it to + - If you have your own engine, you probably want to start from one of the OpenGL example and adapt it to your engine, but you can read the other examples as well. ImGui is highly portable and only requires a few things to run: @@ -41,15 +43,14 @@ to switch to a software rendered cursor when an interactive drag is in progress. Also note that some setup or GPU drivers may be causing extra lag (possibly by enforcing triple buffering), leaving you with no option but sadness/anger (Intel GPU drivers were reported as such). -opengl_example/ - OpenGL example, using GLFW + fixed pipeline. - This is simple and should work for all OpenGL enabled applications. - Prefer following this example to learn how ImGui works! - (You can use this code in a GL3/GL4 context but make sure you disable the programmable pipeline - by calling "glUseProgram(0)" before ImGui::Render.) +opengl2_example/ + GLFW + OpenGL example (old fixed pipeline). + This is simple to read. Prefer following this example to learn how ImGui works! + (You might be able to use this code in a GL3/GL4 context but make sure you disable the programmable + pipeline by calling "glUseProgram(0)" before ImGui::Render.) opengl3_example/ - OpenGL example, using GLFW/GL3W + programmable pipeline. + GLFW + OpenGL example (programmable pipeline, binding modern functions with GL3W). This uses more modern OpenGL calls and custom shaders. It's more messy. directx9_example/ @@ -68,8 +69,8 @@ apple_example/ On iOS, Using Synergy to access keyboard/mouse data from server computer. Synergy keyboard integration is rather hacky. -sdl_opengl_example/ - SDL2 + OpenGL example. +sdl_opengl2_example/ + SDL2 + OpenGL example (old fixed pipeline). sdl_opengl3_example/ SDL2 + OpenGL3 example. diff --git a/examples/imgui_examples_msvc2010.sln b/examples/imgui_examples_msvc2010.sln index b7e6a252..16f0d60b 100644 --- a/examples/imgui_examples_msvc2010.sln +++ b/examples/imgui_examples_msvc2010.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl_example", "opengl_example\opengl_example.vcxproj", "{9CDA7840-B7A5-496D-A527-E95571496D18}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl2_example", "opengl_example\opengl2_example.vcxproj", "{9CDA7840-B7A5-496D-A527-E95571496D18}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directx9_example", "directx9_example\directx9_example.vcxproj", "{4165A294-21F2-44CA-9B38-E3F935ABADF5}" EndProject diff --git a/examples/opengl_example/Makefile b/examples/opengl2_example/Makefile similarity index 98% rename from examples/opengl_example/Makefile rename to examples/opengl2_example/Makefile index 91d1b142..bd79d1ba 100644 --- a/examples/opengl_example/Makefile +++ b/examples/opengl2_example/Makefile @@ -10,7 +10,7 @@ #CXX = g++ -EXE = opengl_example +EXE = opengl2_example OBJS = main.o imgui_impl_glfw.o OBJS += ../../imgui.o ../../imgui_demo.o ../../imgui_draw.o diff --git a/examples/opengl_example/build_win32.bat b/examples/opengl2_example/build_win32.bat similarity index 100% rename from examples/opengl_example/build_win32.bat rename to examples/opengl2_example/build_win32.bat diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp similarity index 100% rename from examples/opengl_example/imgui_impl_glfw.cpp rename to examples/opengl2_example/imgui_impl_glfw.cpp diff --git a/examples/opengl_example/imgui_impl_glfw.h b/examples/opengl2_example/imgui_impl_glfw.h similarity index 100% rename from examples/opengl_example/imgui_impl_glfw.h rename to examples/opengl2_example/imgui_impl_glfw.h diff --git a/examples/opengl_example/main.cpp b/examples/opengl2_example/main.cpp similarity index 100% rename from examples/opengl_example/main.cpp rename to examples/opengl2_example/main.cpp diff --git a/examples/opengl_example/opengl_example.vcxproj b/examples/opengl2_example/opengl_example.vcxproj similarity index 100% rename from examples/opengl_example/opengl_example.vcxproj rename to examples/opengl2_example/opengl_example.vcxproj diff --git a/examples/opengl_example/opengl_example.vcxproj.filters b/examples/opengl2_example/opengl_example.vcxproj.filters similarity index 100% rename from examples/opengl_example/opengl_example.vcxproj.filters rename to examples/opengl2_example/opengl_example.vcxproj.filters diff --git a/examples/sdl_opengl_example/README.md b/examples/sdl_opengl2_example/README.md similarity index 100% rename from examples/sdl_opengl_example/README.md rename to examples/sdl_opengl2_example/README.md diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp similarity index 100% rename from examples/sdl_opengl_example/imgui_impl_sdl.cpp rename to examples/sdl_opengl2_example/imgui_impl_sdl.cpp diff --git a/examples/sdl_opengl_example/imgui_impl_sdl.h b/examples/sdl_opengl2_example/imgui_impl_sdl.h similarity index 100% rename from examples/sdl_opengl_example/imgui_impl_sdl.h rename to examples/sdl_opengl2_example/imgui_impl_sdl.h diff --git a/examples/sdl_opengl_example/main.cpp b/examples/sdl_opengl2_example/main.cpp similarity index 100% rename from examples/sdl_opengl_example/main.cpp rename to examples/sdl_opengl2_example/main.cpp diff --git a/imgui.cpp b/imgui.cpp index a8cddc64..a52903e2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -80,7 +80,7 @@ - read the FAQ below this section! - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. - call and read ImGui::ShowTestWindow() for demo code demonstrating most features. - - see examples/ folder for standalone sample applications. Prefer reading examples/opengl_example/ first as it is the simplest. + - see examples/ folder for standalone sample applications. Prefer reading examples/opengl2_example/ first as it is the simplest. you may be able to grab and copy a ready made imgui_impl_*** file from the examples/. - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). From 5ae71aa04a530a7444349654917bd1bdb3ac3b85 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Aug 2016 10:25:51 +0200 Subject: [PATCH 286/400] Examples: Renaming opengl_example/ to opengl2_example/ for clarity (1/2 because git) --- examples/.gitignore | 10 +++++----- examples/imgui_examples_msvc2010.sln | 2 +- examples/opengl2_example/build_win32.bat | 2 +- ...{opengl_example.vcxproj => opengl2_example.vcxproj} | 2 +- ...vcxproj.filters => opengl2_example.vcxproj.filters} | 0 5 files changed, 8 insertions(+), 8 deletions(-) rename examples/opengl2_example/{opengl_example.vcxproj => opengl2_example.vcxproj} (99%) rename examples/opengl2_example/{opengl_example.vcxproj.filters => opengl2_example.vcxproj.filters} (100%) diff --git a/examples/.gitignore b/examples/.gitignore index 41704453..54d15398 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -15,11 +15,11 @@ directx11_example/Debug/* directx11_example/Release/* directx11_example/ipch/* directx11_example/x64/* -opengl_example/Debug/* -opengl_example/Release/* -opengl_example/ipch/* -opengl_example/x64/* -opengl_example/opengl_example +opengl2_example/Debug/* +opengl2_example/Release/* +opengl2_example/ipch/* +opengl2_example/x64/* +opengl2_example/opengl_example opengl3_example/Debug/* opengl3_example/Release/* opengl3_example/ipch/* diff --git a/examples/imgui_examples_msvc2010.sln b/examples/imgui_examples_msvc2010.sln index 16f0d60b..8c1cd2a3 100644 --- a/examples/imgui_examples_msvc2010.sln +++ b/examples/imgui_examples_msvc2010.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl2_example", "opengl_example\opengl2_example.vcxproj", "{9CDA7840-B7A5-496D-A527-E95571496D18}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl2_example", "opengl2_example\opengl2_example.vcxproj", "{9CDA7840-B7A5-496D-A527-E95571496D18}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directx9_example", "directx9_example\directx9_example.vcxproj", "{4165A294-21F2-44CA-9B38-E3F935ABADF5}" EndProject diff --git a/examples/opengl2_example/build_win32.bat b/examples/opengl2_example/build_win32.bat index 278381c7..28e6752f 100644 --- a/examples/opengl2_example/build_win32.bat +++ b/examples/opengl2_example/build_win32.bat @@ -1,3 +1,3 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. mkdir Debug -cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include *.cpp ..\..\*.cpp /FeDebug/opengl_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib +cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include *.cpp ..\..\*.cpp /FeDebug/opengl2_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib diff --git a/examples/opengl2_example/opengl_example.vcxproj b/examples/opengl2_example/opengl2_example.vcxproj similarity index 99% rename from examples/opengl2_example/opengl_example.vcxproj rename to examples/opengl2_example/opengl2_example.vcxproj index 4b354b6f..bea2104d 100644 --- a/examples/opengl2_example/opengl_example.vcxproj +++ b/examples/opengl2_example/opengl2_example.vcxproj @@ -20,7 +20,7 @@ {9CDA7840-B7A5-496D-A527-E95571496D18} - opengl_example + opengl2_example diff --git a/examples/opengl2_example/opengl_example.vcxproj.filters b/examples/opengl2_example/opengl2_example.vcxproj.filters similarity index 100% rename from examples/opengl2_example/opengl_example.vcxproj.filters rename to examples/opengl2_example/opengl2_example.vcxproj.filters From b36ba12929713068408b359c11c5fecfeb62bdd8 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Aug 2016 16:20:34 +0200 Subject: [PATCH 287/400] Travis test fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 616d7273..ccdb1942 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,6 @@ before_install: - if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install glfw3; fi script: - - make -C examples/opengl_example + - make -C examples/opengl2_example - make -C examples/opengl3_example From 5def10c3a0a008cba01283411e38a46ba95f37f9 Mon Sep 17 00:00:00 2001 From: Gustav Date: Sat, 27 Aug 2016 00:32:20 +0200 Subject: [PATCH 288/400] Fixed OpenGL error when calling Shutdown without calling NewFrame --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 7011875a..c1944fca 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -279,15 +279,15 @@ void ImGui_ImplSdlGL3_InvalidateDeviceObjects() if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); g_VaoHandle = g_VboHandle = g_ElementsHandle = 0; - glDetachShader(g_ShaderHandle, g_VertHandle); - glDeleteShader(g_VertHandle); + if(g_ShaderHandle && g_VertHandle ) glDetachShader(g_ShaderHandle, g_VertHandle); + if(g_VertHandle ) glDeleteShader(g_VertHandle); g_VertHandle = 0; - glDetachShader(g_ShaderHandle, g_FragHandle); - glDeleteShader(g_FragHandle); + if(g_ShaderHandle && g_FragHandle ) glDetachShader(g_ShaderHandle, g_FragHandle); + if(g_FragHandle ) glDeleteShader(g_FragHandle); g_FragHandle = 0; - glDeleteProgram(g_ShaderHandle); + if(g_ShaderHandle ) glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; if (g_FontTexture) From 99b4f951b91a35fe7ad9a3b0e81961da3fc25e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Sat, 27 Aug 2016 19:08:24 +0200 Subject: [PATCH 289/400] Fix Vulkan example for use when a depth buffer is active. --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index a9c18f33..2a85ceff 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -388,10 +388,10 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) else { VkRect2D scissor; - scissor.offset.x = static_cast(pcmd->ClipRect.x); - scissor.offset.y = static_cast(pcmd->ClipRect.y); - scissor.extent.width = static_cast(pcmd->ClipRect.z - pcmd->ClipRect.x); - scissor.extent.height = static_cast(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? + scissor.offset.x = (int32_t)(pcmd->ClipRect.x); + scissor.offset.y = (int32_t)(pcmd->ClipRect.y); + scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); + scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); vkCmdDrawIndexed(g_CommandBuffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); } @@ -725,6 +725,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() raster_info.polygonMode = VK_POLYGON_MODE_FILL; raster_info.cullMode = VK_CULL_MODE_NONE; raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + raster_info.lineWidth = 1.0f; VkPipelineMultisampleStateCreateInfo ms_info = {}; ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; @@ -740,6 +741,9 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + VkPipelineDepthStencilStateCreateInfo depth_info = {}; + depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + VkPipelineColorBlendStateCreateInfo blend_info = {}; blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; blend_info.attachmentCount = 1; @@ -761,6 +765,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.pViewportState = &viewport_info; info.pRasterizationState = &raster_info; info.pMultisampleState = &ms_info; + info.pDepthStencilState = &depth_info; info.pColorBlendState = &blend_info; info.pDynamicState = &dynamic_state; info.layout = g_PipelineLayout; From 08a9e78da5658e0905103e456c75ae1cf4e66960 Mon Sep 17 00:00:00 2001 From: Gustav Date: Mon, 29 Aug 2016 23:35:56 +0200 Subject: [PATCH 290/400] fixed space issues --- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index c1944fca..7b5f43a9 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -279,15 +279,15 @@ void ImGui_ImplSdlGL3_InvalidateDeviceObjects() if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); g_VaoHandle = g_VboHandle = g_ElementsHandle = 0; - if(g_ShaderHandle && g_VertHandle ) glDetachShader(g_ShaderHandle, g_VertHandle); - if(g_VertHandle ) glDeleteShader(g_VertHandle); + if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); + if (g_VertHandle) glDeleteShader(g_VertHandle); g_VertHandle = 0; - if(g_ShaderHandle && g_FragHandle ) glDetachShader(g_ShaderHandle, g_FragHandle); - if(g_FragHandle ) glDeleteShader(g_FragHandle); + if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle); + if (g_FragHandle) glDeleteShader(g_FragHandle); g_FragHandle = 0; - if(g_ShaderHandle ) glDeleteProgram(g_ShaderHandle); + if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; if (g_FontTexture) From aa0cb13aa427bd511ff0b0437d6715f21869c603 Mon Sep 17 00:00:00 2001 From: Kun Lin Date: Fri, 2 Sep 2016 21:57:31 +0900 Subject: [PATCH 291/400] Correct name for linking opengl3_example According to glfw offcial site, linking `libglfw.3.dylib` etc should use `-lglfw`. Changed this made the compilation on my Mac successfully. --- examples/opengl3_example/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index b8e2d83f..ae31c6b8 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -30,7 +30,7 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" LIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo - LIBS += -L/usr/local/lib -lglfw3 + LIBS += -L/usr/local/lib -lglfw CXXFLAGS = -I../../ -I../libs/gl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include CXXFLAGS += -Wall -Wformat From c0fcf223be0ecef552bbd22a4abf1dba84e40d82 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 3 Sep 2016 19:02:57 +0200 Subject: [PATCH 292/400] Fixed assert triggering when a window has zero rendering but has a callback (#810) --- imgui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a52903e2..1d2c9df7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2541,9 +2541,9 @@ static void AddDrawListToRenderList(ImVector& out_render_list, ImDr } // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. - IM_ASSERT(draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); - IM_ASSERT(draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); - IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = 2 bytes = 64K vertices) // If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly. From 2825eaa0be7a0f735d159a2ec6e02ad75d6f986a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 3 Sep 2016 19:24:57 +0200 Subject: [PATCH 293/400] Examples: Accessing ImVector fields directly, feel less stl-ey and fix renderer side assert when render list only contains a callback (#810) --- examples/allegro5_example/imgui_impl_a5.cpp | 10 +++++----- .../apple_example/imguiex-ios/imgui_impl_ios.mm | 7 ++++--- examples/directx10_example/imgui_impl_dx10.cpp | 12 ++++++------ examples/directx11_example/imgui_impl_dx11.cpp | 12 ++++++------ examples/directx9_example/imgui_impl_dx9.cpp | 14 +++++++------- .../marmalade_example/imgui_impl_marmalade.cpp | 9 ++++----- examples/opengl2_example/imgui_impl_glfw.cpp | 12 ++++++------ examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 7 ++++--- examples/sdl_opengl2_example/imgui_impl_sdl.cpp | 12 ++++++------ .../sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 7 ++++--- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 12 ++++++------ 11 files changed, 58 insertions(+), 56 deletions(-) diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index c7ba1106..f9dade11 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -46,8 +46,8 @@ void ImGui_ImplA5_RenderDrawLists(ImDrawData* draw_data) // FIXME-OPT: Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats static ImVector vertices; - vertices.resize(cmd_list->VtxBuffer.size()); - for (int i = 0; i < cmd_list->VtxBuffer.size(); ++i) + vertices.resize(cmd_list->VtxBuffer.Size); + for (int i = 0; i < cmd_list->VtxBuffer.Size; ++i) { const ImDrawVert &dv = cmd_list->VtxBuffer[i]; ImDrawVertAllegro v; @@ -61,12 +61,12 @@ void ImGui_ImplA5_RenderDrawLists(ImDrawData* draw_data) // FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices // You can also use '#define ImDrawIdx unsigned int' in imconfig.h and request ImGui to output 32-bit indices static ImVector indices; - indices.resize(cmd_list->IdxBuffer.size()); - for (int i = 0; i < cmd_list->IdxBuffer.size(); ++i) + indices.resize(cmd_list->IdxBuffer.Size); + for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i) indices[i] = (int)cmd_list->IdxBuffer.Data[i]; int idx_offset = 0; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) diff --git a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm index b286c4d4..394146b0 100644 --- a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm +++ b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm @@ -648,7 +648,7 @@ static void ImGui_ImplIOS_RenderDrawLists (ImDrawData *draw_data) ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front(); glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - int needed_vtx_size = cmd_list->VtxBuffer.size() * sizeof(ImDrawVert); + const int needed_vtx_size = cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); if (g_VboSize < needed_vtx_size) { // Grow our buffer if needed @@ -659,11 +659,12 @@ static void ImGui_ImplIOS_RenderDrawLists (ImDrawData *draw_data) unsigned char* vtx_data = (unsigned char*)glMapBufferRange(GL_ARRAY_BUFFER, 0, needed_vtx_size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); if (!vtx_data) continue; - memcpy(vtx_data, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); + memcpy(vtx_data, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); glUnmapBuffer(GL_ARRAY_BUFFER); - for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index bccee87e..e6e45d0c 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -87,10 +87,10 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); - memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); - vtx_dst += cmd_list->VtxBuffer.size(); - idx_dst += cmd_list->IdxBuffer.size(); + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; } g_pVB->Unmap(); g_pIB->Unmap(); @@ -189,7 +189,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) @@ -205,7 +205,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) } idx_offset += pcmd->ElemCount; } - vtx_offset += cmd_list->VtxBuffer.size(); + vtx_offset += cmd_list->VtxBuffer.Size; } // Restore modified DX state diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 11f66f0e..6fd75a5c 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -89,10 +89,10 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); - memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); - vtx_dst += cmd_list->VtxBuffer.size(); - idx_dst += cmd_list->IdxBuffer.size(); + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; } ctx->Unmap(g_pVB, 0); ctx->Unmap(g_pIB, 0); @@ -194,7 +194,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) @@ -210,7 +210,7 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) } idx_offset += pcmd->ElemCount; } - vtx_offset += cmd_list->VtxBuffer.size(); + vtx_offset += cmd_list->VtxBuffer.Size; } // Restore modified DX state diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index bb309a86..b009de75 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -73,8 +73,8 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_src = &cmd_list->VtxBuffer[0]; - for (int i = 0; i < cmd_list->VtxBuffer.size(); i++) + const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { vtx_dst->pos[0] = vtx_src->pos.x; vtx_dst->pos[1] = vtx_src->pos.y; @@ -85,8 +85,8 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) vtx_dst++; vtx_src++; } - memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); - idx_dst += cmd_list->IdxBuffer.size(); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + idx_dst += cmd_list->IdxBuffer.Size; } g_pVB->Unlock(); g_pIB->Unlock(); @@ -138,7 +138,7 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) @@ -150,11 +150,11 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) const RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; g_pd3dDevice->SetTexture(0, (LPDIRECT3DTEXTURE9)pcmd->TextureId); g_pd3dDevice->SetScissorRect(&r); - g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vtx_offset, 0, (UINT)cmd_list->VtxBuffer.size(), idx_offset, pcmd->ElemCount/3); + g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, idx_offset, pcmd->ElemCount/3); } idx_offset += pcmd->ElemCount; } - vtx_offset += cmd_list->VtxBuffer.size(); + vtx_offset += cmd_list->VtxBuffer.Size; } // Restore the DX9 state diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index 12d5dfaa..c1856a00 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -40,9 +40,8 @@ void ImGui_Marmalade_RenderDrawLists(ImDrawData* draw_data) for(int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->VtxBuffer.front(); - const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front(); - int nVert = cmd_list->VtxBuffer.size(); + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; + const int nVert = cmd_list->VtxBuffer.Size; CIwFVec2* pVertStream = IW_GX_ALLOC(CIwFVec2, nVert); CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert); CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert); @@ -62,12 +61,12 @@ void ImGui_Marmalade_RenderDrawLists(ImDrawData* draw_data) IwGxSetColStream(pColStream, nVert); IwGxSetNormStream(0); - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { - pcmd->UserCallback(cmd_list,pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index 2d1f5c1a..91181f10 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -73,13 +73,13 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->VtxBuffer.front(); - const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front(); - glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos))); - glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv))); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col))); + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 0e3a754c..865e13a2 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -89,13 +89,14 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) const ImDrawIdx* idx_buffer_offset = 0; glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.size() * sizeof(ImDrawVert), (GLvoid*)&cmd_list->VtxBuffer.front(), GL_STREAM_DRAW); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx), (GLvoid*)&cmd_list->IdxBuffer.front(), GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); - for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp index 63ed9f44..651a480a 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp @@ -62,13 +62,13 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->VtxBuffer.front(); - const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front(); - glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos))); - glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv))); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col))); + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 7011875a..a91f15b6 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -83,13 +83,14 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) const ImDrawIdx* idx_buffer_offset = 0; glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.size() * sizeof(ImDrawVert), (GLvoid*)&cmd_list->VtxBuffer.front(), GL_STREAM_DRAW); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx), (GLvoid*)&cmd_list->IdxBuffer.front(), GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); - for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 2a85ceff..55260044 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -315,10 +315,10 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); - memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); - vtx_dst += cmd_list->VtxBuffer.size(); - idx_dst += cmd_list->IdxBuffer.size(); + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; } VkMappedMemoryRange range[2] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; @@ -378,7 +378,7 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) @@ -397,7 +397,7 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) } idx_offset += pcmd->ElemCount; } - vtx_offset += cmd_list->VtxBuffer.size(); + vtx_offset += cmd_list->VtxBuffer.Size; } } From 3a699e7264820759a4fdcdeb6c3af0e134cdc686 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 5 Sep 2016 13:40:04 +0200 Subject: [PATCH 294/400] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea0d4639..bf59046a 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ dear imgui, [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) -dear imgui (AKA ImGui), is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies). +dear imgui (AKA ImGui), is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies). -ImGui is designed to enable fast iteration and empower programmers to create content creation tools and visualization/debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries. +ImGui is designed to enable fast iteration and empower programmers to create content creation tools and visualization/ debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries. ImGui is particularly suited to integration in realtime 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard. @@ -33,6 +33,8 @@ Your code passes mouse/keyboard inputs and settings to ImGui (see example applic ImGui outputs vertex buffers and simple command-lists that you can render in your application. The number of draw calls and state changes is typically very small. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase. +_A common misunderstanding is that some people think immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes. Some lazy IMGUI-style librairies uses immediate mode rendering. This is NOT what Dear ImGui does, in fact it does quite the contrary. Those concepts are absolutely unrelated._ + ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. Demo From 031d4e689de0baadb63ceb54bfae5eff57817f22 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 Sep 2016 22:52:35 +0200 Subject: [PATCH 295/400] Examples: OpenGL3: Revert Makefile change for OSX for now (#812) --- examples/opengl3_example/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index ae31c6b8..393b025b 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -30,7 +30,8 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" LIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo - LIBS += -L/usr/local/lib -lglfw + LIBS += -L/usr/local/lib -lglfw3 + #LIBS += -L/usr/local/lib -lglfw CXXFLAGS = -I../../ -I../libs/gl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include CXXFLAGS += -Wall -Wformat From bc57fd5d1d6499246f4874cdde8e934868d00627 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 Sep 2016 23:39:52 +0200 Subject: [PATCH 296/400] Examples: OpenGL*: Savnig/restoring existing scissor rectangle for completeness (#807) --- examples/opengl2_example/imgui_impl_glfw.cpp | 2 ++ examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 2 ++ examples/sdl_opengl2_example/imgui_impl_sdl.cpp | 2 ++ examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index 91181f10..a9a64292 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -46,6 +46,7 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -108,6 +109,7 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) glPopMatrix(); glPopAttrib(); glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } static const char* ImGui_ImplGlfw_GetClipboardText() diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 865e13a2..03a4aa01 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -55,6 +55,7 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); @@ -125,6 +126,7 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } static const char* ImGui_ImplGlfwGL3_GetClipboardText() diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp index 651a480a..01e493d0 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp @@ -35,6 +35,7 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -97,6 +98,7 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) glPopMatrix(); glPopAttrib(); glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } static const char* ImGui_ImplSdl_GetClipboardText() diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index a91f15b6..5246ad85 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -49,6 +49,7 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); + GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); @@ -119,6 +120,7 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); + glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } static const char* ImGui_ImplSdlGL3_GetClipboardText() From f6d4ca64734bfe593cd5d1425f53ac4bf178d743 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 Sep 2016 12:02:37 +0200 Subject: [PATCH 297/400] TODO list --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 1d2c9df7..28c35717 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -483,8 +483,9 @@ !- main: make it so that a frame with no window registered won't refocus every window on subsequent frames (~bump LastFrameActive of all windows). - main: IsItemHovered() make it 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: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? - - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now. + - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) + - input text: expose CursorPos in char filter event (#816) - input text: flag to disable live update of the user buffer (also applies to float/int text input) - input text: resize behavior - field could stretch when being edited? hover tooltip shows more text? - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) From b594b25be8082d36128584e9320558ea3850500a Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 8 Sep 2016 09:11:29 +0200 Subject: [PATCH 298/400] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bf59046a..de55a62a 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Your code passes mouse/keyboard inputs and settings to ImGui (see example applic ImGui outputs vertex buffers and simple command-lists that you can render in your application. The number of draw calls and state changes is typically very small. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase. -_A common misunderstanding is that some people think immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes. Some lazy IMGUI-style librairies uses immediate mode rendering. This is NOT what Dear ImGui does, in fact it does quite the contrary. Those concepts are absolutely unrelated._ +_A common misunderstanding is that some people think immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes, as the gui functions as called by the user. Some lazy IMGUI-style librairies may work this way but this is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batchs. It never touches your GPU directly. The draw call batchs are rather optimal and you can render them later, in your app or even remotely._ ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. @@ -172,12 +172,13 @@ Ongoing ImGui development is financially supported on [**Patreon**](http://www.p Double-chocolate sponsors: - Media Molecule - Mobigame +- Insomniac Games (sponsored the gamepad/keyboard navigation branch) Salty caramel supporters: - Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko. Caramel supporters: -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society. +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, [Kit framework](http://svkonsult.se/kit), Josh Faust, Martin Donlon. And other supporters; thanks! From 500d19bfdf7f09c99f4953aa394be9f578e1529d Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 8 Sep 2016 09:12:17 +0200 Subject: [PATCH 299/400] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de55a62a..9aade8c5 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Your code passes mouse/keyboard inputs and settings to ImGui (see example applic ImGui outputs vertex buffers and simple command-lists that you can render in your application. The number of draw calls and state changes is typically very small. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase. -_A common misunderstanding is that some people think immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes, as the gui functions as called by the user. Some lazy IMGUI-style librairies may work this way but this is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batchs. It never touches your GPU directly. The draw call batchs are rather optimal and you can render them later, in your app or even remotely._ +_A common misunderstanding is that some people think immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes, as the gui functions as called by the user. Some lazy IMGUI-style librairies may work this way but this is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are rather optimal and you can render them later, in your app or even remotely._ ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. From 6e6f04f51360bafb753141a30d3efd37b11421be Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Sat, 10 Sep 2016 11:10:23 +0200 Subject: [PATCH 300/400] Fix Mac OS X build and remove cruft from Makefile --- examples/apple_example/imguiex.xcodeproj/project.pbxproj | 8 ++++---- examples/opengl3_example/Makefile | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/apple_example/imguiex.xcodeproj/project.pbxproj b/examples/apple_example/imguiex.xcodeproj/project.pbxproj index 5d7776de..be43fb60 100644 --- a/examples/apple_example/imguiex.xcodeproj/project.pbxproj +++ b/examples/apple_example/imguiex.xcodeproj/project.pbxproj @@ -97,7 +97,7 @@ isa = PBXGroup; children = ( 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */, - 1A1A0F351CB3A1B20090F036 /* opengl_example */, + 1A1A0F351CB3A1B20090F036 /* opengl2_example */, 1A1A0F211CB39FB50090F036 /* AppDelegate.h */, 1A1A0F221CB39FB50090F036 /* AppDelegate.m */, 1A1A0F271CB39FB50090F036 /* Assets.xcassets */, @@ -114,15 +114,15 @@ name = "Supporting Files"; sourceTree = ""; }; - 1A1A0F351CB3A1B20090F036 /* opengl_example */ = { + 1A1A0F351CB3A1B20090F036 /* opengl2_example */ = { isa = PBXGroup; children = ( 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */, 1A1A0F381CB3A1B20090F036 /* imgui_impl_glfw.h */, 1A1A0F391CB3A1B20090F036 /* main.cpp */, ); - name = opengl_example; - path = ../../opengl_example; + name = opengl2_example; + path = ../../opengl2_example; sourceTree = ""; }; 6D1E39141B35EEF10017B40F /* usynergy */ = { diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index 393b025b..c824f99a 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -3,9 +3,10 @@ # Compatible with Ubuntu 14.04.1 and Mac OS X # # -# if you using Mac OS X: -# You'll need glfw -# http://www.glfw.org +# You will need GLFW (http://www.glfw.org) +# +# apt-get install libglfw-dev # Linux +# brew install glfw # Mac OS X # #CXX = g++ @@ -33,7 +34,7 @@ ifeq ($(UNAME_S), Darwin) #APPLE LIBS += -L/usr/local/lib -lglfw3 #LIBS += -L/usr/local/lib -lglfw - CXXFLAGS = -I../../ -I../libs/gl3w -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include + CXXFLAGS = -I../../ -I../libs/gl3w -I/usr/local/include CXXFLAGS += -Wall -Wformat # CXXFLAGS += -D__APPLE__ CFLAGS = $(CXXFLAGS) From 02399852fe18b37e883f7651a3590334fb228b24 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 10 Sep 2016 17:43:07 +0200 Subject: [PATCH 301/400] Examples: OpenGL2: Uploading font texture as RGBA32 to increase compatibility with users shaders for beginners (#824) --- examples/opengl2_example/imgui_impl_glfw.cpp | 4 ++-- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index a9a64292..cd8e60d4 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -161,7 +161,7 @@ bool ImGui_ImplGlfw_CreateDeviceObjects() ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; int width, height; - io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. // Upload texture to graphics system GLint last_texture; @@ -170,7 +170,7 @@ bool ImGui_ImplGlfw_CreateDeviceObjects() glBindTexture(GL_TEXTURE_2D, g_FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 03a4aa01..6552e593 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -178,7 +178,7 @@ bool ImGui_ImplGlfwGL3_CreateFontsTexture() ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. // Upload texture to graphics system GLint last_texture; From 612b17ef57c2feef48be1ce4513c6f6f6953ca37 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 11 Sep 2016 22:02:35 +0200 Subject: [PATCH 302/400] Fixing minor english typos (#827) --- examples/README.txt | 2 +- examples/apple_example/imguiex-ios/imgui_impl_ios.mm | 2 +- examples/directx10_example/imgui_impl_dx10.cpp | 2 +- examples/directx11_example/imgui_impl_dx11.cpp | 2 +- examples/vulkan_example/CMakeLists.txt | 2 +- imgui.cpp | 10 +++++----- imgui.h | 2 +- imgui_demo.cpp | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 5a1c8df4..54be766a 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -38,7 +38,7 @@ ImGui has zero frame of lag for most behaviors and one frame of lag for some beh At 60 FPS your experience should be pleasant. Consider that OS mouse cursors are typically drawn through a specific hardware accelerated route and may feel smoother than other GPU rendered contents. You may experiment with the io.MouseDrawCursor flag to request ImGui to draw a mouse cursor itself, to visualize -the lag between an hardware cursor and a software cursor. It might be beneficial to the user experience +the lag between a hardware cursor and a software cursor. It might be beneficial to the user experience to switch to a software rendered cursor when an interactive drag is in progress. Also note that some setup or GPU drivers may be causing extra lag (possibly by enforcing triple buffering), leaving you with no option but sadness/anger (Intel GPU drivers were reported as such). diff --git a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm index 394146b0..63d7d72c 100644 --- a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm +++ b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm @@ -191,7 +191,7 @@ uSynergyBool ImGui_ConnectFunc(uSynergyCookie cookie) // connect it to the address and port we passed in to getaddrinfo(): int ret = connect(usynergy_sockfd, res->ai_addr, res->ai_addrlen); if (!ret) { - NSLog( @"Connect suceeded..."); + NSLog( @"Connect succeeded..."); } else { NSLog( @"Connect failed, %d", ret ); } diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index e6e45d0c..c604df04 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -345,7 +345,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects() // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) // If you would like to use this DX11 sample code but remove this dependency you can: - // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [prefered solution] + // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 6fd75a5c..b7da6e06 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -347,7 +347,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) // If you would like to use this DX11 sample code but remove this dependency you can: - // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [prefered solution] + // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. diff --git a/examples/vulkan_example/CMakeLists.txt b/examples/vulkan_example/CMakeLists.txt index 3657c829..d05b4516 100644 --- a/examples/vulkan_example/CMakeLists.txt +++ b/examples/vulkan_example/CMakeLists.txt @@ -9,7 +9,7 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES") # GLFW -set(GLFW_DIR ../../../glfw) # Set this to point to a up-to-date GLFW repo +set(GLFW_DIR ../../../glfw) # Set this to point to an up-to-date GLFW repo option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) diff --git a/imgui.cpp b/imgui.cpp index 28c35717..551601fd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -301,7 +301,7 @@ - Elements that are not clickable, such as Text() items don't need an ID. - Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget). - to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer. + to do so they need a unique ID. unique ID are typically derived from a string label, an integer index or a pointer. Button("OK"); // Label = "OK", ID = hash of "OK" Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" @@ -525,7 +525,7 @@ !- popups/menus: clarify usage of popups id, how MenuItem/Selectable closing parent popups affects the ID, etc. this is quite fishy needs improvement! (#331, #402) - popups: add variant using global identifier similar to Begin/End (#402) - popups: border options. richer api like BeginChild() perhaps? (#197) - - tooltip: tooltip that doesn't fit in entire screen seems to lose their "last prefered button" and may teleport when moving mouse + - tooltip: tooltip that doesn't fit in entire screen seems to lose their "last preferred button" and may teleport when moving mouse - menus: local shortcuts, global shortcuts (#456, #126) - menus: icons - menus: menubars: some sort of priority / effect of main menu-bar on desktop size? @@ -6096,7 +6096,7 @@ void ImGui::TreeAdvanceToLabelPos() g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing(); } -// Horizontal distance preceeding label when using TreeNode() or Bullet() +// Horizontal distance preceding label when using TreeNode() or Bullet() float ImGui::GetTreeNodeToLabelSpacing() { ImGuiContext& g = *GImGui; @@ -9420,7 +9420,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border) const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index); KeepAliveID(column_id); const float default_t = column_index / (float)window->DC.ColumnsCount; - const float t = window->DC.StateStorage->GetFloat(column_id, default_t); // Cheaply store our floating point value inside the integer (could store an union into the map?) + const float t = window->DC.StateStorage->GetFloat(column_id, default_t); // Cheaply store our floating point value inside the integer (could store a union into the map?) window->DC.ColumnsData[column_index].OffsetNorm = t; } window->DrawList->ChannelsSplit(window->DC.ColumnsCount); @@ -9532,7 +9532,7 @@ void ImGui::ValueColor(const char* prefix, ImU32 v) } //----------------------------------------------------------------------------- -// PLATFORM DEPENDANT HELPERS +// PLATFORM DEPENDENT HELPERS //----------------------------------------------------------------------------- #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS)) diff --git a/imgui.h b/imgui.h index b85eaeff..c72e8142 100644 --- a/imgui.h +++ b/imgui.h @@ -332,7 +332,7 @@ namespace ImGui 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() - IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceeding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode + IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond = 0); // set next TreeNode/CollapsingHeader open state. IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0d9dbbcf..ae508017 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -896,7 +896,7 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("Basic Horizontal Layout")) { - ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceeding item)"); + ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); // Text ImGui::Text("Two items: Hello"); ImGui::SameLine(); From b397fb507e625e0af7741e73b73d78a92b950931 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Sep 2016 09:18:17 +0200 Subject: [PATCH 303/400] Fixed EndGroup() not restoring offset properly. breaking SameLine() offset (caused by 954c890c6782fda494a3ac36f3c5a591db584cf4) (#829) --- imgui.cpp | 3 ++- imgui_internal.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 551601fd..65788592 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9142,6 +9142,7 @@ void ImGui::BeginGroup() group_data.BackupCursorPos = window->DC.CursorPos; group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; group_data.BackupIndentX = window->DC.IndentX; + group_data.BackupGroupOffsetX = window->DC.GroupOffsetX; group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupLogLinePosY = window->DC.LogLinePosY; @@ -9172,7 +9173,7 @@ void ImGui::EndGroup() window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; window->DC.IndentX = group_data.BackupIndentX; - window->DC.GroupOffsetX = window->DC.IndentX; + window->DC.GroupOffsetX = group_data.BackupGroupOffsetX; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; if (group_data.AdvanceCursor) diff --git a/imgui_internal.h b/imgui_internal.h index dc02f719..8a0b4824 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -257,6 +257,7 @@ struct ImGuiGroupData ImVec2 BackupCursorPos; ImVec2 BackupCursorMaxPos; float BackupIndentX; + float BackupGroupOffsetX; float BackupCurrentLineHeight; float BackupCurrentLineTextBaseOffset; float BackupLogLinePosY; From 0420ab027e7b3a876e8999bde7a94212d1c37463 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 16 Sep 2016 01:09:57 +0200 Subject: [PATCH 304/400] Metrics: Displaying window position + moving extraneous line in IsPopupOpen(). --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 65788592..bdd08a30 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3356,8 +3356,7 @@ void ImGui::EndTooltip() static bool IsPopupOpen(ImGuiID id) { ImGuiContext& g = *GImGui; - const bool is_open = g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; - return is_open; + return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id; } // Mark popup as open (toggle toward open state). @@ -9728,6 +9727,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) return; NodeDrawList(window->DrawList, "DrawList"); + ImGui::BulletText("Pos: (%.1f,%.1f)", window->Pos.x, window->Pos.y); ImGui::BulletText("Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); ImGui::BulletText("Scroll: (%.2f,%.2f)", window->Scroll.x, window->Scroll.y); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); From 87d99fce6bd2924bb48d2d4fd05318165dd88f17 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Sep 2016 09:32:21 +0200 Subject: [PATCH 305/400] ImFont: CalcWordWrapPositionA() fixed font scaling with fallback character. (followup to 86666489df97d40edef64196db43963cd0ba335f) --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 45549298..27f8b8e5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1841,7 +1841,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } } - const float char_width = ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] * scale : FallbackXAdvance; + const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance) * scale; if (ImCharIsSpace(c)) { if (inside_word) From 6e87f071b8642456b1c29210b02a75d4c10de8b7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 Sep 2016 12:41:21 +0200 Subject: [PATCH 306/400] Shutdown() clear out some remaining pointers (#836) --- imgui.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index bdd08a30..ed0c13d6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2335,10 +2335,13 @@ void ImGui::Shutdown() } g.Windows.clear(); g.WindowsSortBuffer.clear(); + g.CurrentWindow = NULL; g.CurrentWindowStack.clear(); g.FocusedWindow = NULL; g.HoveredWindow = NULL; g.HoveredRootWindow = NULL; + g.ActiveIdWindow = NULL; + g.MovedWindow = NULL; for (int i = 0; i < g.Settings.Size; i++) ImGui::MemFree(g.Settings[i].Name); g.Settings.clear(); @@ -2347,6 +2350,8 @@ void ImGui::Shutdown() g.FontStack.clear(); g.OpenPopupStack.clear(); g.CurrentPopupStack.clear(); + g.SetNextWindowSizeConstraintCallback = NULL; + g.SetNextWindowSizeConstraintCallbackUserData = NULL; for (int i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) g.RenderDrawLists[i].clear(); g.OverlayDrawList.ClearFreeMemory(); From 5c3f8b12b92a2b30b194b52d68e8a8aebc7b08dd Mon Sep 17 00:00:00 2001 From: Frederik De Bleser Date: Wed, 21 Sep 2016 20:26:27 +0200 Subject: [PATCH 307/400] Update link to Synergy repo The Synergy repository has moved from synergy/synergy to symless/synergy. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aade8c5..88b9baeb 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ See the FAQ in imgui.cpp for answers. How do you use ImGui on a platform that may not have a mouse or keyboard? -I recommend using [Synergy](http://synergy-project.org) ([sources](https://github.com/synergy/synergy)). In particular, the _src/micro/uSynergy.c_ file contains a small client that you can use on any platform to connect to your host PC. You can seamlessly use your PC input devices from a video game console or a tablet. ImGui allows to increase the hit box of widgets (via the _TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse to allow optimising for screen real-estate. +I recommend using [Synergy](http://synergy-project.org) ([sources](https://github.com/symless/synergy)). In particular, the _src/micro/uSynergy.c_ file contains a small client that you can use on any platform to connect to your host PC. You can seamlessly use your PC input devices from a video game console or a tablet. ImGui allows to increase the hit box of widgets (via the _TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse to allow optimising for screen real-estate. Can you create elaborate/serious tools with ImGui? From 7f51929dc40aaba9a3a6574d90b3138cace5884b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Sep 2016 09:06:09 +0200 Subject: [PATCH 308/400] Tools: binary_to_compressed_c: Avoid ?? trigraphs sequences in string outputs (#839) --- extra_fonts/binary_to_compressed_c.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/extra_fonts/binary_to_compressed_c.cpp b/extra_fonts/binary_to_compressed_c.cpp index 57b24079..338acc5b 100644 --- a/extra_fonts/binary_to_compressed_c.cpp +++ b/extra_fonts/binary_to_compressed_c.cpp @@ -79,11 +79,18 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_b if (use_base85_encoding) { fprintf(out, "static const char %s_%sdata_base85[%d+1] =\n \"", symbol, compressed_str, (int)((compressed_sz+3)/4)*5); - for (int i = 0; i < compressed_sz; i += 4) + char prev_c = 0; + for (int src_i = 0; src_i < compressed_sz; src_i += 4) { - unsigned int d = *(unsigned int*)(compressed + i); - fprintf(out, "%c%c%c%c%c", Encode85Byte(d), Encode85Byte(d/85), Encode85Byte(d/7225), Encode85Byte(d/614125), Encode85Byte(d/52200625)); - if ((i % 112) == 112-4) + // This is made a little more complicated by the fact that ??X sequences are interpreted as trigraphs by old C/C++ compilers. So we need to escape pairs of ??. + unsigned int d = *(unsigned int*)(compressed + src_i); + for (unsigned int n5 = 0; n5 < 5; n5++, d /= 85) + { + char c = Encode85Byte(d); + fprintf(out, (c == '?' && prev_c == '?') ? "\\%c" : "%c", c); + prev_c = c; + } + if ((src_i % 112) == 112-4) fprintf(out, "\"\n \""); } fprintf(out, "\";\n\n"); From 35c6fd682fd42d4e19f881cbcdc6a4a50ece0a29 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Sep 2016 09:09:07 +0200 Subject: [PATCH 309/400] Inhibiting a ??e sequence in the embedded font. Shouldn't be treated as a trigraph but consistent with encoder (#839) --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 27f8b8e5..64c1be5f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2324,7 +2324,7 @@ static const char proggy_clean_ttf_compressed_data_base85[11980+1] = "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" From c5b8c6303aa9699c7fcc9965636a6eeed5aec507 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:06:14 +0200 Subject: [PATCH 310/400] Refactor PushStyleVar/PopStyleVar so it is constant time + can receive integers (yet unused) (#842) --- imgui.cpp | 105 +++++++++++++++++++++++++++-------------------- imgui.h | 4 +- imgui_internal.h | 17 +++++--- 3 files changed, 74 insertions(+), 52 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ed0c13d6..572c69a5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -563,7 +563,6 @@ - style: color-box not always square? - style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps to other settings? avoid implementing duplicate helpers such as SmallCheckbox(), etc. - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation). - - style/opt: PopStyleVar could be optimized by having GetStyleVar returns the type, using a table mapping stylevar enum to data type. - style: global scale setting. - style: WindowPadding needs to be EVEN needs the 0.5 multiplier probably have a subtle effect on clip rectangle - text: simple markup language for color change? @@ -4646,7 +4645,7 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) ImGuiContext& g = *GImGui; ImGuiColMod backup; backup.Col = idx; - backup.PreviousValue = g.Style.Colors[idx]; + backup.BackupValue = g.Style.Colors[idx]; g.ColorModifiers.push_back(backup); g.Style.Colors[idx] = col; } @@ -4657,64 +4656,78 @@ void ImGui::PopStyleColor(int count) while (count > 0) { ImGuiColMod& backup = g.ColorModifiers.back(); - g.Style.Colors[backup.Col] = backup.PreviousValue; + g.Style.Colors[backup.Col] = backup.BackupValue; g.ColorModifiers.pop_back(); count--; } } -static float* GetStyleVarFloatAddr(ImGuiStyleVar idx) +struct ImGuiStyleVarInfo { - ImGuiContext& g = *GImGui; - switch (idx) - { - case ImGuiStyleVar_Alpha: return &g.Style.Alpha; - case ImGuiStyleVar_WindowRounding: return &g.Style.WindowRounding; - case ImGuiStyleVar_ChildWindowRounding: return &g.Style.ChildWindowRounding; - case ImGuiStyleVar_FrameRounding: return &g.Style.FrameRounding; - case ImGuiStyleVar_IndentSpacing: return &g.Style.IndentSpacing; - case ImGuiStyleVar_GrabMinSize: return &g.Style.GrabMinSize; - } - return NULL; + ImGuiDataType Type; + ImU32 Offset; + void* GetVarPtr() const { return (void*)((unsigned char*)&GImGui->Style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] = +{ + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildWindowRounding) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, + { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, +}; + +static const void* GetStyleVarPtr(ImGuiStyleVar idx, ImGuiDataType type) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_Count_); + const ImGuiStyleVarInfo* info = &GStyleVarInfo[idx]; + return (info->Type == type) ? info->GetVarPtr() : NULL; } -static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx) +void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) { - ImGuiContext& g = *GImGui; - switch (idx) + if (int* pvar = (int*)GetStyleVarPtr(idx, ImGuiDataType_Int)) { - case ImGuiStyleVar_WindowPadding: return &g.Style.WindowPadding; - case ImGuiStyleVar_WindowMinSize: return &g.Style.WindowMinSize; - case ImGuiStyleVar_FramePadding: return &g.Style.FramePadding; - case ImGuiStyleVar_ItemSpacing: return &g.Style.ItemSpacing; - case ImGuiStyleVar_ItemInnerSpacing: return &g.Style.ItemInnerSpacing; + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; } - return NULL; + if (float* pvarf = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + { + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvarf)); + *pvarf = (float)val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a int. } void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { - ImGuiContext& g = *GImGui; - float* pvar = GetStyleVarFloatAddr(idx); - IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float. - ImGuiStyleMod backup; - backup.Var = idx; - backup.PreviousValue = ImVec2(*pvar, 0.0f); - g.StyleModifiers.push_back(backup); - *pvar = val; + if (float* pvar = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + { + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a float. } - void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { - ImGuiContext& g = *GImGui; - ImVec2* pvar = GetStyleVarVec2Addr(idx); - IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2. - ImGuiStyleMod backup; - backup.Var = idx; - backup.PreviousValue = *pvar; - g.StyleModifiers.push_back(backup); - *pvar = val; + if (ImVec2* pvar = (ImVec2*)GetStyleVarPtr(idx, ImGuiDataType_Float2)) + { + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2. } void ImGui::PopStyleVar(int count) @@ -4723,10 +4736,12 @@ void ImGui::PopStyleVar(int count) while (count > 0) { ImGuiStyleMod& backup = g.StyleModifiers.back(); - if (float* pvar_f = GetStyleVarFloatAddr(backup.Var)) - *pvar_f = backup.PreviousValue.x; - else if (ImVec2* pvar_v = GetStyleVarVec2Addr(backup.Var)) - *pvar_v = backup.PreviousValue; + IM_ASSERT(backup.VarIdx >= 0 && backup.VarIdx < ImGuiStyleVar_Count_); + const ImGuiStyleVarInfo* info = &GStyleVarInfo[backup.VarIdx]; + void* pvar = info->GetVarPtr(); + if (info->Type == ImGuiDataType_Float) (*(float*)pvar) = backup.BackupFloat[0]; + else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)pvar) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]); + else if (info->Type == ImGuiDataType_Int) (*(int*)pvar) = backup.BackupInt[0]; g.StyleModifiers.pop_back(); count--; } diff --git a/imgui.h b/imgui.h index c72e8142..8081f262 100644 --- a/imgui.h +++ b/imgui.h @@ -176,6 +176,7 @@ namespace ImGui IMGUI_API void PopFont(); IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, int val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); IMGUI_API void PopStyleVar(int count = 1); @@ -646,7 +647,8 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ItemSpacing, // ImVec2 ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ImGuiStyleVar_IndentSpacing, // float - ImGuiStyleVar_GrabMinSize // float + ImGuiStyleVar_GrabMinSize, // float + ImGuiStyleVar_Count_ }; enum ImGuiAlign_ diff --git a/imgui_internal.h b/imgui_internal.h index 8a0b4824..826fbfbd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -75,6 +75,7 @@ extern IMGUI_API ImGuiContext* GImGui; // current implicit ImGui context po #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) #define IM_PI 3.14159265358979323846f +#define IM_OFFSETOF(_TYPE,_ELM) ((size_t)&(((_TYPE*)0)->_ELM)) // Helpers: UTF-8 <> wchar IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count @@ -192,7 +193,8 @@ enum ImGuiPlotType enum ImGuiDataType { ImGuiDataType_Int, - ImGuiDataType_Float + ImGuiDataType_Float, + ImGuiDataType_Float2, }; // 2D axis aligned bounding-box @@ -241,14 +243,17 @@ struct IMGUI_API ImRect struct ImGuiColMod { ImGuiCol Col; - ImVec4 PreviousValue; + ImVec4 BackupValue; }; -// Stacked style modifier, backup of modified data so we can restore it +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. struct ImGuiStyleMod { - ImGuiStyleVar Var; - ImVec2 PreviousValue; + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } }; // Stacked data for BeginGroup()/EndGroup() @@ -705,7 +710,7 @@ namespace ImGui IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); // NB: All position are in absolute pixels coordinates (not window coordinates) - // FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp! + // FIXME: All those functions are a mess and needs to be refactored into something decent. AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); From 281898e82e880e212453bf5c12139df9add3f535 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:14:10 +0200 Subject: [PATCH 311/400] Tidying up PushStyleVar/PopStyleVar() a little more (#842) --- imgui.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 572c69a5..f5faa159 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4684,25 +4684,27 @@ static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] = { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, }; -static const void* GetStyleVarPtr(ImGuiStyleVar idx, ImGuiDataType type) +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) { IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_Count_); - const ImGuiStyleVarInfo* info = &GStyleVarInfo[idx]; - return (info->Type == type) ? info->GetVarPtr() : NULL; + return &GStyleVarInfo[idx]; } void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) { - if (int* pvar = (int*)GetStyleVarPtr(idx, ImGuiDataType_Int)) + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Int) { + int* pvar = (int*)var_info->GetVarPtr(); GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; } - if (float* pvarf = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + if (var_info->Type == ImGuiDataType_Float) { - GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvarf)); - *pvarf = (float)val; + float* pvar = (float*)var_info->GetVarPtr(); + GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = (float)val; return; } IM_ASSERT(0); // Called function with wrong-type? Variable is not a int. @@ -4710,8 +4712,10 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { - if (float* pvar = (float*)GetStyleVarPtr(idx, ImGuiDataType_Float)) + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float) { + float* pvar = (float*)var_info->GetVarPtr(); GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; @@ -4721,8 +4725,10 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { - if (ImVec2* pvar = (ImVec2*)GetStyleVarPtr(idx, ImGuiDataType_Float2)) + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float2) { + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(); GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; @@ -4736,12 +4742,10 @@ void ImGui::PopStyleVar(int count) while (count > 0) { ImGuiStyleMod& backup = g.StyleModifiers.back(); - IM_ASSERT(backup.VarIdx >= 0 && backup.VarIdx < ImGuiStyleVar_Count_); - const ImGuiStyleVarInfo* info = &GStyleVarInfo[backup.VarIdx]; - void* pvar = info->GetVarPtr(); - if (info->Type == ImGuiDataType_Float) (*(float*)pvar) = backup.BackupFloat[0]; - else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)pvar) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]); - else if (info->Type == ImGuiDataType_Int) (*(int*)pvar) = backup.BackupInt[0]; + const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); + if (info->Type == ImGuiDataType_Float) (*(float*)info->GetVarPtr()) = backup.BackupFloat[0]; + else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)info->GetVarPtr()) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]); + else if (info->Type == ImGuiDataType_Int) (*(int*)info->GetVarPtr()) = backup.BackupInt[0]; g.StyleModifiers.pop_back(); count--; } From 02cea0c3c3a7ac245f663e0ceb6f048eb0048405 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:16:19 +0200 Subject: [PATCH 312/400] Comment --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f5faa159..938b6111 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5583,7 +5583,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 pos = window->DC.CursorPos; - if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y; ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); From de9f8944ea757d65770411297ab0a4e9ca0ab09f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 11:38:04 +0200 Subject: [PATCH 313/400] Internal RenderTextClipped() merged optional/rate clip_min* clip_max* into clip_rect* --- imgui.cpp | 20 ++++++++++++-------- imgui_internal.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 938b6111..194ebbca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2866,8 +2866,9 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end } } +// Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImVec2* clip_min, const ImVec2* clip_max) +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImRect* clip_rect) { // Hide anything after a '##' string const char* text_display_end = FindRenderedTextEnd(text, text_end); @@ -2882,11 +2883,13 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons ImVec2 pos = pos_min; const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); - if (!clip_max) clip_max = &pos_max; + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); - if (!clip_min) clip_min = &pos_min; else need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - // Align + // Align whole block (we should defer that to the better rendering function) if (align & ImGuiAlign_Center) pos.x = ImMax(pos.x, (pos.x + pos_max.x - text_size.x) * 0.5f); else if (align & ImGuiAlign_Right) pos.x = ImMax(pos.x, pos_max.x - text_size.x); if (align & ImGuiAlign_VCenter) pos.y = ImMax(pos.y, (pos.y + pos_max.y - text_size.y) * 0.5f); @@ -4306,14 +4309,15 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us ImVec2 text_min = window->Pos + style.FramePadding; ImVec2 text_max = window->Pos + ImVec2(window->Size.x - style.FramePadding.x, style.FramePadding.y*2 + text_size.y); - ImVec2 clip_max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() + ImRect clip_rect; + clip_rect.Max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() bool pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0; bool pad_right = (p_open != NULL); if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; - ImVec2 clip_min = ImVec2(text_min.x, window->Pos.y); - RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_min, &clip_max); + clip_rect.Min = ImVec2(text_min.x, window->Pos.y); + RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() @@ -7222,7 +7226,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) - RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb.Min, &bb.Max); + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb); } bool ImGui::Checkbox(const char* label, bool* v) diff --git a/imgui_internal.h b/imgui_internal.h index 826fbfbd..d0dedc47 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,7 +714,7 @@ namespace ImGui // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); From 0f303d363ab03bcc14178ed4aa9b7b6d0dad7e54 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 12:19:15 +0200 Subject: [PATCH 314/400] Refactor text alignment options to use ImVec2, removed ImGuiAlign (#842, #222) --- imgui.cpp | 68 +++++++++++++++++------------------------------- imgui.h | 16 ++---------- imgui_internal.h | 2 +- 3 files changed, 27 insertions(+), 59 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 194ebbca..f9edf25c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -150,6 +150,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. @@ -729,7 +730,7 @@ ImGuiStyle::ImGuiStyle() WindowPadding = ImVec2(8,8); // Padding within a window WindowMinSize = ImVec2(32,32); // Minimum window size WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows - WindowTitleAlign = ImGuiAlign_Left; // Alignment for title bar text + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). @@ -2868,7 +2869,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end // Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImRect* clip_rect) +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) { // Hide anything after a '##' string const char* text_display_end = FindRenderedTextEnd(text, text_end); @@ -2889,10 +2890,9 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - // Align whole block (we should defer that to the better rendering function) - if (align & ImGuiAlign_Center) pos.x = ImMax(pos.x, (pos.x + pos_max.x - text_size.x) * 0.5f); - else if (align & ImGuiAlign_Right) pos.x = ImMax(pos.x, pos_max.x - text_size.x); - if (align & ImGuiAlign_VCenter) pos.y = ImMax(pos.y, (pos.y + pos_max.y - text_size.y) * 0.5f); + // Align whole block (we should defer that to the better rendering function + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); // Render if (need_clipping) @@ -4307,15 +4307,15 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (!(flags & ImGuiWindowFlags_NoCollapse)) RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true); - ImVec2 text_min = window->Pos + style.FramePadding; - ImVec2 text_max = window->Pos + ImVec2(window->Size.x - style.FramePadding.x, style.FramePadding.y*2 + text_size.y); + ImVec2 text_min = window->Pos; + ImVec2 text_max = window->Pos + ImVec2(window->Size.x, style.FramePadding.y*2 + text_size.y); ImRect clip_rect; clip_rect.Max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() - bool pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0; - bool pad_right = (p_open != NULL); - if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left; - if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; - if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x; + float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : 0.0f; + float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : 0.0f; + if (style.WindowTitleAlign.x > 0.0f) pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); + text_min.x += pad_left; + text_max.x -= pad_right; clip_rect.Min = ImVec2(text_min.x, window->Pos.y); RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); } @@ -4694,26 +4694,6 @@ static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) return &GStyleVarInfo[idx]; } -void ImGui::PushStyleVar(ImGuiStyleVar idx, int val) -{ - const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type == ImGuiDataType_Int) - { - int* pvar = (int*)var_info->GetVarPtr(); - GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; - return; - } - if (var_info->Type == ImGuiDataType_Float) - { - float* pvar = (float*)var_info->GetVarPtr(); - GImGui->StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = (float)val; - return; - } - IM_ASSERT(0); // Called function with wrong-type? Variable is not a int. -} - void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); @@ -5470,7 +5450,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) // Render const char* value_text_begin = &g.TempBuffer[0]; const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); - RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImGuiAlign_VCenter); + RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } @@ -5603,7 +5583,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, ImGuiAlign_Center | ImGuiAlign_VCenter); + RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, style.ButtonTextAlign); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -5970,12 +5950,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const char log_prefix[] = "\n##"; const char log_suffix[] = "##"; LogRenderedText(text_pos, log_prefix, log_prefix+3); - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); LogRenderedText(text_pos, log_suffix+1, log_suffix+3); } else { - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); } } else @@ -6602,7 +6582,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6649,7 +6629,7 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float // For the vertical slider we allow centered text to overlap the frame padding char value_buf[64]; char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6899,7 +6879,7 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); - RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -7150,7 +7130,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge // Text overlay if (overlay_text) - RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImGuiAlign_Center); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -7226,7 +7206,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over ImVec2 overlay_size = CalcTextSize(overlay, NULL); if (overlay_size.x > 0.0f) - RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb); + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb); } bool ImGui::Checkbox(const char* label, bool* v) @@ -8440,7 +8420,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi { const char* item_text; if (items_getter(data, *current_item, &item_text)) - RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, item_text, NULL, NULL); + RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, item_text, NULL, NULL, ImVec2(0.0f,0.0f)); } if (label_size.x > 0) @@ -8586,7 +8566,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl } if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); - RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size); + RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size, ImVec2(0.0f,0.0f)); if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); // Automatically close popups diff --git a/imgui.h b/imgui.h index 8081f262..48785078 100644 --- a/imgui.h +++ b/imgui.h @@ -70,7 +70,6 @@ typedef void* ImTextureID; // user data to identify a texture (this is typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_ typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_ typedef int ImGuiKey; // a key identifier (ImGui-side enum) // enum ImGuiKey_ -typedef int ImGuiAlign; // alignment // enum ImGuiAlign_ typedef int ImGuiColorEditMode; // color edit mode for ColorEdit*() // enum ImGuiColorEditMode_ typedef int ImGuiMouseCursor; // a mouse cursor identifier // enum ImGuiMouseCursor_ typedef int ImGuiWindowFlags; // window flags for Begin*() // enum ImGuiWindowFlags_ @@ -176,7 +175,6 @@ namespace ImGui IMGUI_API void PopFont(); IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, int val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); IMGUI_API void PopStyleVar(int count = 1); @@ -651,16 +649,6 @@ enum ImGuiStyleVar_ ImGuiStyleVar_Count_ }; -enum ImGuiAlign_ -{ - ImGuiAlign_Left = 1 << 0, - ImGuiAlign_Center = 1 << 1, - ImGuiAlign_Right = 1 << 2, - ImGuiAlign_Top = 1 << 3, - ImGuiAlign_VCenter = 1 << 4, - ImGuiAlign_Default = ImGuiAlign_Left | ImGuiAlign_Top -}; - // Enumeration for ColorEditMode() // FIXME-OBSOLETE: Will be replaced by future color/picker api enum ImGuiColorEditMode_ @@ -701,7 +689,7 @@ struct ImGuiStyle ImVec2 WindowPadding; // Padding within a window ImVec2 WindowMinSize; // Minimum window size float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows - ImGuiAlign WindowTitleAlign; // Alignment for title bar text + ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. float ChildWindowRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets) float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). @@ -712,7 +700,7 @@ struct ImGuiStyle float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar float ScrollbarRounding; // Radius of grab corners for scrollbar - float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. diff --git a/imgui_internal.h b/imgui_internal.h index d0dedc47..076ec413 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,7 +714,7 @@ namespace ImGui // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); From 56cdbe434d320e7c7294c77ab786b4ca224d796f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 12:53:13 +0200 Subject: [PATCH 315/400] Style: Added ButtonTextAlign, ImGuiStyleVar_ButtonTextAlign (#842) --- imgui.cpp | 10 ++++++---- imgui.h | 2 ++ imgui_demo.cpp | 7 +++++-- imgui_internal.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f9edf25c..71cc3a42 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -743,6 +743,7 @@ ImGuiStyle::ImGuiStyle() ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. DisplaySafeAreaPadding = ImVec2(4,4); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. @@ -2890,7 +2891,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); - // Align whole block (we should defer that to the better rendering function + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); @@ -4686,6 +4687,7 @@ static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] = { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, + { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, }; static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) @@ -5583,7 +5585,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, style.ButtonTextAlign); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -5950,12 +5952,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const char log_prefix[] = "\n##"; const char log_suffix[] = "##"; LogRenderedText(text_pos, log_prefix, log_prefix+3); - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); LogRenderedText(text_pos, log_suffix+1, log_suffix+3); } else { - RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size, ImVec2(0.0f,0.0f)); + RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size); } } else diff --git a/imgui.h b/imgui.h index 48785078..d6b12b27 100644 --- a/imgui.h +++ b/imgui.h @@ -646,6 +646,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ImGuiStyleVar_IndentSpacing, // float ImGuiStyleVar_GrabMinSize, // float + ImGuiStyleVar_ButtonTextAlign, // flags ImGuiAlign_* ImGuiStyleVar_Count_ }; @@ -702,6 +703,7 @@ struct ImGuiStyle float ScrollbarRounding; // Radius of grab corners for scrollbar float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered. ImVec2 DisplayWindowPadding; // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ae508017..75cd92c5 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -790,7 +790,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::Separator(); ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth(); ImGui::SameLine(); - ImGui::SliderInt("Sample count", &display_count, 1, 500); + ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); @@ -1632,7 +1632,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::TreePop(); } - if (ImGui::TreeNode("Sizes")) + if (ImGui::TreeNode("Settings")) { ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 16.0f, "%.0f"); @@ -1647,6 +1647,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 16.0f, "%.0f"); + ImGui::Text("Alignment"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index 076ec413..f4a0d688 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -714,7 +714,7 @@ namespace ImGui // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); IMGUI_API void RenderBullet(ImVec2 pos); From f2699de24241bedad05b18dfe5beba623ba77dcf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 14:18:10 +0200 Subject: [PATCH 316/400] Fix using IsItemActive() after EndGroup() or any widget using groups (#840, #479) --- imgui.cpp | 19 ++++++++++++------- imgui_internal.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 71cc3a42..afd58724 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7609,11 +7609,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const ImGuiIO& io = g.IO; const ImGuiStyle& style = g.Style; - const ImGuiID id = window->GetID(label); const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn + BeginGroup(); + const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); @@ -7622,7 +7624,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 ImGuiWindow* draw_window = window; if (is_multiline) { - BeginGroup(); if (!BeginChildFrame(id, frame_bb.GetSize())) { EndChildFrame(); @@ -8149,8 +8150,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line EndChildFrame(); EndGroup(); - if (g.ActiveId == id || is_currently_scrolling) // Set LastItemId which was lost by EndChild/EndGroup, so user can use IsItemActive() - window->DC.LastItemId = g.ActiveId; } if (is_password) @@ -8204,7 +8203,7 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal)) extra_flags |= ImGuiInputTextFlags_CharsDecimal; extra_flags |= ImGuiInputTextFlags_AutoSelectAll; - if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) + if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format); // Step buttons @@ -9155,6 +9154,7 @@ 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.AdvanceCursor = true; window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX; @@ -9166,15 +9166,15 @@ void ImGui::BeginGroup() void ImGui::EndGroup() { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - ImGuiStyle& style = GetStyle(); IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls ImGuiGroupData& group_data = window->DC.GroupStack.back(); ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); - group_bb.Max.y -= style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. + group_bb.Max.y -= g.Style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. group_bb.Max = ImMax(group_bb.Min, group_bb.Max); window->DC.CursorPos = group_data.BackupCursorPos; @@ -9192,6 +9192,11 @@ void ImGui::EndGroup() ItemAdd(group_bb, NULL); } + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will function 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. + if (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow) + window->DC.LastItemId = g.ActiveId; + window->DC.GroupStack.pop_back(); //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug diff --git a/imgui_internal.h b/imgui_internal.h index f4a0d688..4bfec9dc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -266,6 +266,7 @@ struct ImGuiGroupData float BackupCurrentLineHeight; float BackupCurrentLineTextBaseOffset; float BackupLogLinePosY; + bool BackupActiveIdIsAlive; bool AdvanceCursor; }; From 6def01be5df16e17d71f81a8d4083a0f48d04a8d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 14:32:38 +0200 Subject: [PATCH 317/400] Fixed IsItemActive() lagging by one frame on initial widget activation (#840) --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index afd58724..c33efc98 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1828,6 +1828,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) g.ActiveId = id; g.ActiveIdAllowOverlap = false; g.ActiveIdIsJustActivated = true; + if (id) + g.ActiveIdIsAlive = true; g.ActiveIdWindow = window; } From d7c518e6ccc642af225e4c63ba672dfa5844eaeb Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 15:22:41 +0200 Subject: [PATCH 318/400] ShowStyleEditor: show font map / grid in more details. --- imgui_demo.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 75cd92c5..d68ab8ac 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -71,7 +71,13 @@ static void ShowHelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered()) - ImGui::SetTooltip(desc); + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(450.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } } void ImGui::ShowUserGuide() @@ -1731,7 +1737,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::PopFont(); if (ImGui::TreeNode("Details")) { - ImGui::DragFloat("font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this font + ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font + ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) @@ -1739,6 +1746,39 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImFontConfig* cfg = &font->ConfigData[config_i]; ImGui::BulletText("Input %d: \'%s\'\nOversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); } + if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + { + // Display all glyphs of the fonts in separate pages of 256 characters + const ImFont::Glyph* glyph_fallback = font->FallbackGlyph; // Forcefully/dodgily make FindGlyph() return NULL on fallback, which isn't the default behavior. + font->FallbackGlyph = NULL; + for (int base = 0; base < 0x10000; base += 256) + { + int count = 0; + for (int n = 0; n < 256; n++) + count += font->FindGlyph((ImWchar)(base + n)) ? 1 : 0; + if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base+255, count, count > 1 ? "glyphs" : "glyph")) + { + float cell_spacing = style.ItemSpacing.y; + ImVec2 cell_size(font->FontSize * 1, font->FontSize * 1); + ImVec2 base_pos = ImGui::GetCursorScreenPos(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 256; n++) + { + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size.x + cell_spacing), base_pos.y + (n / 16) * (cell_size.y + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size.x, cell_p1.y + cell_size.y); + const ImFont::Glyph* glyph = font->FindGlyph((ImWchar)(base+n));; + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50)); + font->RenderChar(draw_list, cell_size.x, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. + if (ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) + ImGui::SetTooltip("U+%04X: %s", base+n, glyph ? "Present" : "Missing"); + } + ImGui::Dummy(ImVec2((cell_size.x + cell_spacing) * 16, (cell_size.y + cell_spacing) * 16)); + ImGui::TreePop(); + } + } + font->FallbackGlyph = glyph_fallback; + ImGui::TreePop(); + } ImGui::TreePop(); } ImGui::TreePop(); From 82dcdc9dfc663294f2973f4c7b7313a3ff092187 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 25 Sep 2016 15:52:04 +0200 Subject: [PATCH 319/400] ShowStyleEditor: tweak font map display to show glyph details when hovered. --- imgui_demo.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d68ab8ac..e4247e6f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1769,8 +1769,16 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) const ImFont::Glyph* glyph = font->FindGlyph((ImWchar)(base+n));; draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50)); font->RenderChar(draw_list, cell_size.x, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. - if (ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) - ImGui::SetTooltip("U+%04X: %s", base+n, glyph ? "Present" : "Missing"); + if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) + { + ImGui::BeginTooltip(); + ImGui::Text("Codepoint: U+%04X", base+n); + ImGui::Separator(); + ImGui::Text("XAdvance+1: %.1f", glyph->XAdvance); + ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); + ImGui::EndTooltip(); + } } ImGui::Dummy(ImVec2((cell_size.x + cell_spacing) * 16, (cell_size.y + cell_spacing) * 16)); ImGui::TreePop(); From d75d2b1871831377faef836f4be798575732e412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cicho=C5=84?= Date: Fri, 5 Aug 2016 11:04:05 +0200 Subject: [PATCH 320/400] Introduce IMGUI_USE_BGRA_PACKED_COLOR in imconfig.h. When IMGUI_USE_BGRA_PACKED_COLOR is defined packed color hold in ImU32 use BGRA format instead RGBA. --- imconfig.h | 3 +++ imgui.cpp | 14 +++++++++----- imgui.h | 13 ++++++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/imconfig.h b/imconfig.h index 33cbadd1..2a956d37 100644 --- a/imconfig.h +++ b/imconfig.h @@ -26,6 +26,9 @@ //---- Don't define obsolete functions names //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS +//---- Pack colors to BGRA instead of RGBA (remove need to post process vertex buffer in back ends) +//#define IMGUI_USE_BGRA_PACKED_COLOR + //---- Implement STB libraries in a namespace to avoid conflicts //#define IMGUI_STB_NAMESPACE ImGuiStb diff --git a/imgui.cpp b/imgui.cpp index c33efc98..3fb183b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1195,16 +1195,20 @@ int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_e ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) { float s = 1.0f/255.0f; - return ImVec4((in & 0xFF) * s, ((in >> 8) & 0xFF) * s, ((in >> 16) & 0xFF) * s, (in >> 24) * s); + return ImVec4( + ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); } ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) { ImU32 out; - out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)); - out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << 8; - out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << 16; - out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << 24; + out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; return out; } diff --git a/imgui.h b/imgui.h index d6b12b27..15149c1b 100644 --- a/imgui.h +++ b/imgui.h @@ -1091,7 +1091,18 @@ struct ImGuiListClipper //----------------------------------------------------------------------------- // Helpers macros to generate 32-bits encoded colors -#define IM_COL32(R,G,B,A) (((ImU32)(A)<<24) | ((ImU32)(B)<<16) | ((ImU32)(G)<<8) | ((ImU32)(R))) +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)< Date: Sat, 6 Aug 2016 10:57:52 +0200 Subject: [PATCH 321/400] Apply Omar feedback and convert remaining 0xAABBGGRR's into IM_COL32(RR,GG,BB,AA) format. --- imgui.cpp | 12 ++++++------ imgui.h | 36 ++++++++++++++++++------------------ imgui_demo.cpp | 10 +++++----- imgui_draw.cpp | 6 +++--- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3fb183b4..07b4be9a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8849,7 +8849,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); moving_within_opened_triangle = ImIsPointInTriangle(g.IO.MousePos, ta, tb, tc); - //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? 0x80008000 : 0x80000080); window->DrawList->PopClipRect(); // Debug + //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug } } @@ -9205,7 +9205,7 @@ void ImGui::EndGroup() window->DC.GroupStack.pop_back(); - //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // Debug } // Gets back to previous line and continue with horizontal layout @@ -9545,10 +9545,10 @@ void ImGui::ValueColor(const char* prefix, ImU32 v) SameLine(); ImVec4 col; - col.x = (float)((v >> 0) & 0xFF) / 255.0f; - col.y = (float)((v >> 8) & 0xFF) / 255.0f; - col.z = (float)((v >> 16) & 0xFF) / 255.0f; - col.w = (float)((v >> 24) & 0xFF) / 255.0f; + col.x = (float)((v >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f; + col.y = (float)((v >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f; + col.z = (float)((v >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f; + col.w = (float)((v >> IM_COL32_A_SHIFT) & 0xFF) / 255.0f; ColorButton(col, true); } diff --git a/imgui.h b/imgui.h index 15149c1b..843b3bea 100644 --- a/imgui.h +++ b/imgui.h @@ -827,6 +827,23 @@ struct ImGuiIO // Helpers //----------------------------------------------------------------------------- +// Helpers macros to generate 32-bits encoded colors +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)< like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). // Our implementation does NOT call c++ constructors because we don't use them in ImGui. Don't use this class as a straight std::vector replacement in your code! template @@ -1044,7 +1061,7 @@ struct ImColor ImColor() { Value.x = Value.y = Value.z = Value.w = 0.0f; } ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f/255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; } - ImColor(ImU32 rgba) { float sc = 1.0f/255.0f; Value.x = (float)(rgba&0xFF) * sc; Value.y = (float)((rgba>>8)&0xFF) * sc; Value.z = (float)((rgba>>16)&0xFF) * sc; Value.w = (float)(rgba >> 24) * sc; } + ImColor(ImU32 rgba) { float sc = 1.0f/255.0f; Value.x = (float)((rgba>>IM_COL32_R_SHIFT)&0xFF) * sc; Value.y = (float)((rgba>>IM_COL32_G_SHIFT)&0xFF) * sc; Value.z = (float)((rgba>>IM_COL32_B_SHIFT)&0xFF) * sc; Value.w = (float)((rgba>>IM_COL32_A_SHIFT)&0xFF) * sc; } ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } ImColor(const ImVec4& col) { Value = col; } inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } @@ -1090,23 +1107,6 @@ struct ImGuiListClipper // Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. //----------------------------------------------------------------------------- -// Helpers macros to generate 32-bits encoded colors -#ifdef IMGUI_USE_BGRA_PACKED_COLOR -#define IM_COL32_R_SHIFT 16 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 0 -#define IM_COL32_A_SHIFT 24 -#else -#define IM_COL32_R_SHIFT 0 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 16 -#define IM_COL32_A_SHIFT 24 -#endif -#define IM_COL32(R,G,B,A) (((ImU32)(A)<AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), 0xFFFF00FF); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); ImGui::Text("lazy dog. This paragraph is made to fit within %.0f pixels. The quick brown fox jumps over the lazy dog.", wrap_width); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), 0xFF00FFFF); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); ImGui::PopTextWrapPos(); ImGui::Text("Test paragraph 2:"); pos = ImGui::GetCursorScreenPos(); - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), 0xFFFF00FF); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); ImGui::Text("aaaaaaaa bbbbbbbb, cccccccc,dddddddd. eeeeeeee ffffffff. gggggggg!hhhhhhhh"); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), 0xFF00FFFF); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); ImGui::PopTextWrapPos(); ImGui::TreePop(); @@ -2063,7 +2063,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) } draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y)); // clip lines within the canvas (if we resize it, etc.) for (int i = 0; i < points.Size - 1; i += 2) - draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i+1].x, canvas_pos.y + points[i+1].y), 0xFF00FFFF, 2.0f); + draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i+1].x, canvas_pos.y + points[i+1].y), IM_COL32(255,255,0,255), 2.0f); draw_list->PopClipRect(); if (adding_preview) points.pop_back(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 64c1be5f..4e70dbcd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -429,7 +429,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 { // Anti-aliased stroke const float AA_SIZE = 1.0f; - const ImU32 col_trans = col & 0x00ffffff; + const ImU32 col_trans = col & IM_COL32(255,255,255,0); const int idx_count = thick_line ? count*18 : count*12; const int vtx_count = thick_line ? points_count*4 : points_count*3; @@ -602,7 +602,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun { // Anti-aliased Fill const float AA_SIZE = 1.0f; - const ImU32 col_trans = col & 0x00ffffff; + const ImU32 col_trans = col & IM_COL32(255, 255, 255, 0); const int idx_count = (points_count-2)*3 + points_count*6; const int vtx_count = (points_count*2); PrimReserve(idx_count, vtx_count); @@ -1119,7 +1119,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid const unsigned char* src = pixels; unsigned int* dst = TexPixelsRGBA32; for (int n = TexWidth * TexHeight; n > 0; n--) - *dst++ = ((unsigned int)(*src++) << 24) | 0x00FFFFFF; + *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); } *out_pixels = (unsigned char*)TexPixelsRGBA32; From dfe4683c176f49866ccdbf815abcc023489a7981 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 1 Oct 2016 14:10:24 +0200 Subject: [PATCH 322/400] EndGroup(): Made IsItemHovered() work when an item was activated within the group (#849) (loosely follows #840) --- imgui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index c33efc98..91a2b1d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9196,8 +9196,11 @@ void ImGui::EndGroup() // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will function 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. - if (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow) + const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow); + if (active_id_within_group) window->DC.LastItemId = g.ActiveId; + if (active_id_within_group && g.HoveredId == g.ActiveId) + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = true; window->DC.GroupStack.pop_back(); From 68c81739bff860300b763d942a55c3a5697d5d9b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 1 Oct 2016 14:29:12 +0200 Subject: [PATCH 323/400] Minor tidying up following merge BGRA color PR (#844) --- imgui.cpp | 12 +++--------- imgui.h | 34 +++++++++++++++++----------------- imgui_draw.cpp | 2 +- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c1987be8..5157a2cd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1216,14 +1216,14 @@ ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * alpha_mul; - return ImGui::ColorConvertFloat4ToU32(c); + return ColorConvertFloat4ToU32(c); } ImU32 ImGui::GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; - return ImGui::ColorConvertFloat4ToU32(c); + return ColorConvertFloat4ToU32(c); } // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 @@ -9546,13 +9546,7 @@ void ImGui::ValueColor(const char* prefix, ImU32 v) { Text("%s: %08X", prefix, v); SameLine(); - - ImVec4 col; - col.x = (float)((v >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f; - col.y = (float)((v >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f; - col.z = (float)((v >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f; - col.w = (float)((v >> IM_COL32_A_SHIFT) & 0xFF) / 255.0f; - ColorButton(col, true); + ColorButton(ColorConvertU32ToFloat4(v), true); } //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 843b3bea..7ef8bd23 100644 --- a/imgui.h +++ b/imgui.h @@ -827,23 +827,6 @@ struct ImGuiIO // Helpers //----------------------------------------------------------------------------- -// Helpers macros to generate 32-bits encoded colors -#ifdef IMGUI_USE_BGRA_PACKED_COLOR -#define IM_COL32_R_SHIFT 16 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 0 -#define IM_COL32_A_SHIFT 24 -#else -#define IM_COL32_R_SHIFT 0 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 16 -#define IM_COL32_A_SHIFT 24 -#endif -#define IM_COL32(R,G,B,A) (((ImU32)(A)< like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug). // Our implementation does NOT call c++ constructors because we don't use them in ImGui. Don't use this class as a straight std::vector replacement in your code! template @@ -1051,6 +1034,23 @@ struct ImGuiSizeConstraintCallbackData ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. }; +// Helpers macros to generate 32-bits encoded colors +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)< Date: Sat, 1 Oct 2016 14:59:28 +0200 Subject: [PATCH 324/400] Examples: GLFW+OpenGL3: Fixed Shutdown() calling GL functions with NULL parameters if NewFrame was never called (#800) --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 6552e593..0cc0cba5 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -282,15 +282,15 @@ void ImGui_ImplGlfwGL3_InvalidateDeviceObjects() if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); g_VaoHandle = g_VboHandle = g_ElementsHandle = 0; - glDetachShader(g_ShaderHandle, g_VertHandle); - glDeleteShader(g_VertHandle); + if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); + if (g_VertHandle) glDeleteShader(g_VertHandle); g_VertHandle = 0; - glDetachShader(g_ShaderHandle, g_FragHandle); - glDeleteShader(g_FragHandle); + if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle); + if (g_FragHandle) glDeleteShader(g_FragHandle); g_FragHandle = 0; - glDeleteProgram(g_ShaderHandle); + if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; if (g_FontTexture) From a2487bc1432925f33c5fc5ffe67bbd69bc31b5e1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 1 Oct 2016 15:16:17 +0200 Subject: [PATCH 325/400] Minor tweaks --- imgui.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5157a2cd..063ab487 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4072,7 +4072,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (window_pos_center) { // Center (any sort of window) - SetWindowPos(ImMax(style.DisplaySafeAreaPadding, fullscreen_rect.GetCenter() - window->SizeFull * 0.5f)); + SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, fullscreen_rect.GetCenter() - window->SizeFull * 0.5f), 0); } else if (flags & ImGuiWindowFlags_ChildMenu) { @@ -4870,14 +4870,13 @@ static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiSetCond co void ImGui::SetWindowPos(const ImVec2& pos, ImGuiSetCond cond) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); SetWindowPos(window, pos, cond); } void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond) { - ImGuiWindow* window = FindWindowByName(name); - if (window) + if (ImGuiWindow* window = FindWindowByName(name)) SetWindowPos(window, pos, cond); } From 05b580e691aafa3b904e305b5332f2f20bd7ac74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 2 Oct 2016 17:25:09 +0200 Subject: [PATCH 326/400] Tools: Fixed binary_to_compressed_c.cpp not to use different types on both sides of ternary op (#856) --- extra_fonts/binary_to_compressed_c.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/extra_fonts/binary_to_compressed_c.cpp b/extra_fonts/binary_to_compressed_c.cpp index 338acc5b..4d0471a8 100644 --- a/extra_fonts/binary_to_compressed_c.cpp +++ b/extra_fonts/binary_to_compressed_c.cpp @@ -173,17 +173,12 @@ static void stb__write(unsigned char v) ++stb__outbytes; } -#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) - -static void stb_out2(stb_uint v) -{ - stb_out(v >> 8); - stb_out(v); -} +//#define stb_out(v) (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v))) +#define stb_out(v) do { if (stb__out) *stb__out++ = (stb_uchar) (v); else stb__write((stb_uchar) (v)); } while (0) +static void stb_out2(stb_uint v) { stb_out(v >> 8); stb_out(v); } static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); } -static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); -stb_out(v >> 8 ); stb_out(v); } +static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16); stb_out(v >> 8 ); stb_out(v); } static void outliterals(stb_uchar *in, int numlit) { From 1d7e05327b52e3443332d944a2fe6933ee249b13 Mon Sep 17 00:00:00 2001 From: Jeongseok Lee Date: Thu, 6 Oct 2016 14:48:47 -0400 Subject: [PATCH 327/400] Fix clang warning: unknown warning group '-Wreserved-id-macro' --- imgui_demo.cpp | 4 +++- imgui_draw.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 506b0f2d..e2ede9bd 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -30,7 +30,9 @@ #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. -#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#endif #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0db105fe..5c265c58 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -39,7 +39,9 @@ #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wreserved-id-macro") #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#endif #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function From e07d45709fa2c429b85e6f495e3d7d0b6f052ea8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Oct 2016 09:49:52 +0200 Subject: [PATCH 328/400] ImDrawList: Uses IM_COL32_A_MASK macro instead of hardcoded zero alpha testing (#844) --- imgui.h | 2 ++ imgui_draw.cpp | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/imgui.h b/imgui.h index 7ef8bd23..feb9bf99 100644 --- a/imgui.h +++ b/imgui.h @@ -1040,11 +1040,13 @@ struct ImGuiSizeConstraintCallbackData #define IM_COL32_G_SHIFT 8 #define IM_COL32_B_SHIFT 0 #define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 #else #define IM_COL32_R_SHIFT 0 #define IM_COL32_G_SHIFT 8 #define IM_COL32_B_SHIFT 16 #define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 #endif #define IM_COL32(R,G,B,A) (((ImU32)(A)<> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(a + ImVec2(0.5f,0.5f)); PathLineTo(b + ImVec2(0.5f,0.5f)); @@ -809,7 +809,7 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thic // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly. void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners, float thickness) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners); PathStroke(col, true, thickness); @@ -817,7 +817,7 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; if (rounding > 0.0f) { @@ -833,7 +833,7 @@ void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, floa void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) { - if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) >> 24) == 0) + if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) return; const ImVec2 uv = GImGui->FontTexUvWhitePixel; @@ -848,7 +848,7 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(a); @@ -860,7 +860,7 @@ void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, cons void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(a); @@ -872,7 +872,7 @@ void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(a); @@ -883,7 +883,7 @@ void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(a); @@ -894,7 +894,7 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; @@ -904,7 +904,7 @@ void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int nu void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments; @@ -914,7 +914,7 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; PathLineTo(pos0); @@ -924,7 +924,7 @@ void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImV void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; if (text_end == NULL) @@ -959,7 +959,7 @@ void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, c void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col) { - if ((col >> 24) == 0) + if ((col & IM_COL32_A_MASK) == 0) return; // FIXME-OPT: This is wasting draw calls. @@ -1169,7 +1169,7 @@ static void Decode85(const unsigned char* src, unsigned char* dst) while (*src) { unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4])))); - dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianess. + dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. src += 5; dst += 4; } From 51111b0ed59b2336a6f5dcba90d416b871809998 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Oct 2016 10:27:19 +0200 Subject: [PATCH 329/400] FAQ clarified the ClipRect entry a little --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 063ab487..5ffdc606 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -294,7 +294,7 @@ Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height). + A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) A: Yes. A primer on the use of labels/IDs in ImGui.. From fa73e5aa0e8c7346b1eaa44db6ef85e6d1898494 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 8 Oct 2016 12:43:30 +0200 Subject: [PATCH 330/400] Plot: Fixed calling with values_count == 0 --- imgui.cpp | 99 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5ffdc606..cec87afa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7080,59 +7080,62 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); - int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); - - // Tooltip on hover - int v_hovered = -1; - if (IsHovered(inner_bb, 0)) + if (values_count > 0) { - const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); - const int v_idx = (int)(t * item_count); - IM_ASSERT(v_idx >= 0 && v_idx < values_count); + int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); - const float v0 = values_getter(data, (v_idx + values_offset) % values_count); - const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); - if (plot_type == ImGuiPlotType_Lines) - SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); - else if (plot_type == ImGuiPlotType_Histogram) - SetTooltip("%d: %8.4g", v_idx, v0); - v_hovered = v_idx; - } - - const float t_step = 1.0f / (float)res_w; - - float v0 = values_getter(data, (0 + values_offset) % values_count); - float t0 = 0.0f; - ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) / (scale_max - scale_min)) ); // Point in the normalized space of our target rectangle - - const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); - const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); - - for (int n = 0; n < res_w; n++) - { - const float t1 = t0 + t_step; - const int v1_idx = (int)(t0 * item_count + 0.5f); - IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); - const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); - const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) / (scale_max - scale_min)) ); - - // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. - ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); - ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, 1.0f)); - if (plot_type == ImGuiPlotType_Lines) + // Tooltip on hover + int v_hovered = -1; + if (IsHovered(inner_bb, 0)) { - window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); - } - else if (plot_type == ImGuiPlotType_Histogram) - { - if (pos1.x >= pos0.x + 2.0f) - pos1.x -= 1.0f; - window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); + const int v_idx = (int)(t * item_count); + IM_ASSERT(v_idx >= 0 && v_idx < values_count); + + const float v0 = values_getter(data, (v_idx + values_offset) % values_count); + const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); + if (plot_type == ImGuiPlotType_Lines) + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); + else if (plot_type == ImGuiPlotType_Histogram) + SetTooltip("%d: %8.4g", v_idx, v0); + v_hovered = v_idx; } - t0 = t1; - tp0 = tp1; + const float t_step = 1.0f / (float)res_w; + + float v0 = values_getter(data, (0 + values_offset) % values_count); + float t0 = 0.0f; + ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) / (scale_max - scale_min)) ); // Point in the normalized space of our target rectangle + + const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); + const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); + + for (int n = 0; n < res_w; n++) + { + const float t1 = t0 + t_step; + const int v1_idx = (int)(t0 * item_count + 0.5f); + IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); + const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); + const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) / (scale_max - scale_min)) ); + + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, 1.0f)); + if (plot_type == ImGuiPlotType_Lines) + { + window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + } + else if (plot_type == ImGuiPlotType_Histogram) + { + if (pos1.x >= pos0.x + 2.0f) + pos1.x -= 1.0f; + window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base); + } + + t0 = t1; + tp0 = tp1; + } } // Text overlay From 5957af8a80cf28984f533d726e2d289d247278c0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 9 Oct 2016 10:08:03 +0200 Subject: [PATCH 331/400] Fixed not using IM_ARRAYSIZE() where appropriate --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cec87afa..6cbe5d37 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3490,11 +3490,11 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; - char name[32]; + char name[20]; if (flags & ImGuiWindowFlags_ChildMenu) - ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.Size); // Recycle windows based on depth + ImFormatString(name, IM_ARRAYSIZE(name), "##menu_%d", g.CurrentPopupStack.Size); // Recycle windows based on depth else - ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame + ImFormatString(name, IM_ARRAYSIZE(name), "##popup_%08x", id); // Not recycling, so we can close/open during the same frame bool is_open = ImGui::Begin(name, NULL, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) @@ -8250,7 +8250,7 @@ bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, if (decimal_precision < 0) strcpy(display_format, "%f"); // Ideally we'd have a minimum decimal precision of 1 to visually denote that this is a float, while hiding non-significant digits? %f doesn't have a minimum of 1 else - ImFormatString(display_format, 16, "%%.%df", decimal_precision); + ImFormatString(display_format, IM_ARRAYSIZE(display_format), "%%.%df", decimal_precision); return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), display_format, extra_flags); } From abaada4224cb636c0c323f18d979dab9ece85a78 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 9 Oct 2016 10:31:39 +0200 Subject: [PATCH 332/400] Removed the inconsistent shadow under RenderCollapseTriangle() (~#707) --- imgui.cpp | 10 ++++------ imgui_internal.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6cbe5d37..197ef199 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2929,7 +2929,7 @@ void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, } // Render a triangle to denote expanded/collapsed state -void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale, bool shadow) +void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -2953,8 +2953,6 @@ void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale, bool c = center + ImVec2(-0.500f,-0.866f)*r; } - if (shadow && (window->Flags & ImGuiWindowFlags_ShowBorders) != 0) - window->DrawList->AddTriangleFilled(a+ImVec2(2,2), b+ImVec2(2,2), c+ImVec2(2,2), GetColorU32(ImGuiCol_BorderShadow)); window->DrawList->AddTriangleFilled(a, b, c, GetColorU32(ImGuiCol_Text)); } @@ -4312,7 +4310,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us const ImVec2 text_size = CalcTextSize(name, NULL, true); if (!(flags & ImGuiWindowFlags_NoCollapse)) - RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true); + RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f); ImVec2 text_min = window->Pos; ImVec2 text_max = window->Pos + ImVec2(window->Size.x, style.FramePadding.y*2 + text_size.y); @@ -5950,7 +5948,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { // Framed type RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), is_open, 1.0f, true); + RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), is_open, 1.0f); if (g.LogEnabled) { // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. @@ -5974,7 +5972,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y)); else if (!(flags & ImGuiTreeNodeFlags_Leaf)) - RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open, 0.70f, false); + RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open, 0.70f); if (g.LogEnabled) LogRenderedText(text_pos, ">"); RenderText(text_pos, label, label_end, false); diff --git a/imgui_internal.h b/imgui_internal.h index 4bfec9dc..d3633b5f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -717,7 +717,7 @@ namespace ImGui IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); - IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false); + IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f); IMGUI_API void RenderBullet(ImVec2 pos); IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col); IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. From d567595dde622eee52df934004ccc9f4681a29a8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 9 Oct 2016 10:35:01 +0200 Subject: [PATCH 333/400] ImDrawList: AddRect(), PathRect() default rounded_corner 0x0F->~0/-1 so it appears less obscure in IDE completions --- imgui.h | 8 ++++---- imgui_draw.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index feb9bf99..6a2fb337 100644 --- a/imgui.h +++ b/imgui.h @@ -1190,8 +1190,8 @@ struct ImDrawList // Primitives IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); - IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F, float thickness = 1.0f); // a: upper-left, b: lower-right - IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners = 0x0F); // a: upper-left, b: lower-right + IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ~0, float thickness = 1.0f); // a: upper-left, b: lower-right, rounding_corners_flags: 4-bits corresponding to which corner to round + IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ~0); // a: upper-left, b: lower-right IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); IMGUI_API void AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness = 1.0f); IMGUI_API void AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col); @@ -1213,9 +1213,9 @@ struct ImDrawList inline void PathFill(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col, true); PathClear(); } inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness, true); PathClear(); } IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); - IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); - IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners = 0x0F); + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners_flags = ~0); // rounding_corners_flags: 4-bits corresponding to which corner to round // Channels // - Use to simulate layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0533292a..ade41777 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -807,21 +807,21 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thic } // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly. -void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners, float thickness) +void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness) { if ((col & IM_COL32_A_MASK) == 0) return; - PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners); + PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners_flags); PathStroke(col, true, thickness); } -void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners) +void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags) { if ((col & IM_COL32_A_MASK) == 0) return; if (rounding > 0.0f) { - PathRect(a, b, rounding, rounding_corners); + PathRect(a, b, rounding, rounding_corners_flags); PathFill(col); } else From 1810b3ff38f4b92c98403a69a41b3a5ce0f07210 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 9 Oct 2016 10:56:23 +0200 Subject: [PATCH 334/400] Added ImGuiCorner enum to clarify some internal code --- imgui.cpp | 13 ++++++------- imgui_internal.h | 9 +++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 197ef199..2683c557 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4192,8 +4192,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f; - // Window background - // Default alpha + // Window background, Default Alpha ImGuiCol bg_color_idx = ImGuiCol_WindowBg; if ((flags & ImGuiWindowFlags_ComboBox) != 0) bg_color_idx = ImGuiCol_ComboBg; @@ -4206,19 +4205,19 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us bg_color.w = bg_alpha; bg_color.w *= style.Alpha; if (bg_color.w > 0.0f) - window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 15 : 4|8); + window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImGuiCorner_All : ImGuiCorner_BottomLeft|ImGuiCorner_BottomRight); // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32((g.FocusedWindow && window->RootNonPopupWindow == g.FocusedWindow->RootNonPopupWindow) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, 1|2); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32((g.FocusedWindow && window->RootNonPopupWindow == g.FocusedWindow->RootNonPopupWindow) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, ImGuiCorner_TopLeft|ImGuiCorner_TopRight); // Menu bar if (flags & ImGuiWindowFlags_MenuBar) { ImRect menu_bar_rect = window->MenuBarRect(); - window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, 1|2); if (flags & ImGuiWindowFlags_ShowBorders) window->DrawList->AddLine(menu_bar_rect.GetBL()-ImVec2(0,0), menu_bar_rect.GetBR()-ImVec2(0,0), GetColorU32(ImGuiCol_Border)); + window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImGuiCorner_TopLeft|ImGuiCorner_TopRight); } // Scrollbars @@ -4426,9 +4425,9 @@ static void Scrollbar(ImGuiWindow* window, bool horizontal) float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; int window_rounding_corners; if (horizontal) - window_rounding_corners = 8 | (other_scrollbar ? 0 : 4); + window_rounding_corners = ImGuiCorner_BottomLeft | (other_scrollbar ? 0 : ImGuiCorner_BottomRight); else - window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? 2 : 0) | (other_scrollbar ? 0 : 4); + window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImGuiCorner_TopRight : 0) | (other_scrollbar ? 0 : ImGuiCorner_BottomRight); window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_ScrollbarBg), window_rounding, window_rounding_corners); bb.Reduce(ImVec2(ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f))); diff --git a/imgui_internal.h b/imgui_internal.h index d3633b5f..08f206ad 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -197,6 +197,15 @@ enum ImGuiDataType ImGuiDataType_Float2, }; +enum ImGuiCorner +{ + ImGuiCorner_TopLeft = 1 << 0, // 1 + ImGuiCorner_TopRight = 1 << 1, // 2 + ImGuiCorner_BottomRight = 1 << 2, // 4 + ImGuiCorner_BottomLeft = 1 << 3, // 8 + ImGuiCorner_All = 0x0F +}; + // 2D axis aligned bounding-box // NB: we can't rely on ImVec2 math operators being available here struct IMGUI_API ImRect From 4de35b4f30ab353a2c7a2fec4058e3717d59236a Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 9 Oct 2016 10:58:38 +0200 Subject: [PATCH 335/400] Removed left-over empty op --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 2683c557..26be158d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4216,7 +4216,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us { ImRect menu_bar_rect = window->MenuBarRect(); if (flags & ImGuiWindowFlags_ShowBorders) - window->DrawList->AddLine(menu_bar_rect.GetBL()-ImVec2(0,0), menu_bar_rect.GetBR()-ImVec2(0,0), GetColorU32(ImGuiCol_Border)); + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border)); window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImGuiCorner_TopLeft|ImGuiCorner_TopRight); } From 31dc7d8d635b94e4bfdd0834de05c54efa36fd69 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Oct 2016 18:03:37 +0200 Subject: [PATCH 336/400] Added ImGuiMouseCursor_None for usage by app/binding --- imgui.h | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.h b/imgui.h index 6a2fb337..34c70aa0 100644 --- a/imgui.h +++ b/imgui.h @@ -664,6 +664,7 @@ enum ImGuiColorEditMode_ // Enumeration for GetMouseCursor() enum ImGuiMouseCursor_ { + ImGuiMouseCursor_None = -1, ImGuiMouseCursor_Arrow = 0, ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. ImGuiMouseCursor_Move, // Unused From cb7e1c18b57092da146307557b3e9d1fead7430f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Oct 2016 22:37:59 +0200 Subject: [PATCH 337/400] Separator: Fixed zero-height bounding box resulting in clipping when at top of clipping rectangle (#860) --- imgui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 26be158d..3bb3241b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9092,8 +9092,8 @@ void ImGui::Separator() if (!window->DC.GroupStack.empty()) x1 += window->DC.IndentX; - const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y)); - ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit // FIXME: Height should be 1.0f not 0.0f ? + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f)); + ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout. if (!ItemAdd(bb, NULL)) { if (window->DC.ColumnsCount > 1) @@ -9101,7 +9101,7 @@ void ImGui::Separator() return; } - window->DrawList->AddLine(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border)); + window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Border)); ImGuiContext& g = *GImGui; if (g.LogEnabled) From d649bc485b4035244f82bf7d312dd3d4280cedee Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 15 Oct 2016 11:18:29 +0200 Subject: [PATCH 338/400] Minor comments --- imgui.h | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index 34c70aa0..dad5abaa 100644 --- a/imgui.h +++ b/imgui.h @@ -804,7 +804,7 @@ struct ImGuiIO int MetricsActiveWindows; // Number of visible windows (exclude child windows) //------------------------------------------------------------------ - // [Internal] ImGui will maintain those fields for you + // [Private] ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ ImVec2 MousePosPrev; // Previous mouse position @@ -950,10 +950,9 @@ struct ImGuiTextBuffer }; // Helper: Simple Key->value storage -// - Store collapse state for a tree (Int 0/1) -// - Store color edit options (Int using values in ImGuiColorEditMode enum). -// - Custom user storage for temporary values. // Typically you don't have to worry about this since a storage is held within each Window. +// We use it to e.g. store collapse state for a tree (Int 0/1), store color edit options. +// You can use it as custom user storage for temporary values. // Declare your own storage if: // - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). // - You want to store custom debug data easily without adding or editing structures in your code. @@ -985,9 +984,8 @@ struct ImGuiStorage // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. - // - A typical use case where this is convenient: + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; - // - You can also use this to quickly create temporary editable values during a session of using Edit&Continue, without restarting your application. IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); @@ -1056,8 +1054,8 @@ struct ImGuiSizeConstraintCallbackData // ImColor() helper to implicity converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float) // Prefer using IM_COL32() macros if you want a guaranteed compile-time ImU32 for usage with ImDrawList API. -// Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. -// None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. +// **Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. +// **None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. struct ImColor { ImVec4 Value; @@ -1170,7 +1168,7 @@ struct ImDrawList ImVector VtxBuffer; // Vertex buffer. // [Internal, used while building lists] - const char* _OwnerName; // Pointer to owner window's name (if any) for debugging + const char* _OwnerName; // Pointer to owner window's name for debugging unsigned int _VtxCurrentIdx; // [Internal] == VtxBuffer.Size ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) @@ -1181,7 +1179,7 @@ struct ImDrawList int _ChannelsCount; // [Internal] number of active channels (1+) ImVector _Channels; // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size) - ImDrawList() { _OwnerName = NULL; Clear(); } + ImDrawList() { _OwnerName = NULL; Clear(); } ~ImDrawList() { ClearFreeMemory(); } IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) IMGUI_API void PushClipRectFullScreen(); @@ -1394,9 +1392,7 @@ struct ImFont #pragma clang diagnostic pop #endif -//---- Include imgui_user.h at the end of imgui.h -//---- So you can include code that extends ImGui using any of the types declared above. -//---- (also convenient for user to only explicitly include vanilla imgui.h) +// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) #ifdef IMGUI_INCLUDE_IMGUI_USER_H #include "imgui_user.h" #endif From 0d3f8807c78b21bcf6dfef1a6987d1eb70419027 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 15 Oct 2016 11:36:43 +0200 Subject: [PATCH 339/400] Added a void* user_data parameter to Clipboard function handlers. (#875) --- examples/allegro5_example/imgui_impl_a5.cpp | 3 +++ .../imguiex-ios/imgui_impl_ios.mm | 4 ++- .../imgui_impl_marmalade.cpp | 26 ++++++++----------- examples/opengl2_example/imgui_impl_glfw.cpp | 9 ++++--- .../opengl3_example/imgui_impl_glfw_gl3.cpp | 9 ++++--- .../sdl_opengl2_example/imgui_impl_sdl.cpp | 5 ++-- .../imgui_impl_sdl_gl3.cpp | 5 ++-- .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 9 ++++--- imgui.cpp | 25 +++++++++--------- imgui.h | 5 ++-- 10 files changed, 54 insertions(+), 46 deletions(-) diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index f9dade11..9a04ff9c 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -1,6 +1,9 @@ // ImGui Allegro 5 bindings // In this binding, ImTextureID is used to store a 'ALLEGRO_BITMAP*' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. +// TODO: +// - Clipboard is not supported. + // 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(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. diff --git a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm index 63d7d72c..893dbf97 100644 --- a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm +++ b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm @@ -3,6 +3,9 @@ // Providing a standalone iOS application with Synergy integration makes this sample more verbose than others. It also hasn't been tested as much. // Refer to other examples to get an easier understanding of how to integrate ImGui into your existing application. +// TODO: +// - Clipboard is not supported. + #import #import @@ -288,7 +291,6 @@ void ImGui_ClipboardCallback(uSynergyCookie cookie, enum uSynergyClipboardFormat printf("Synergy: clipboard callback TODO\n" ); } - @interface ImGuiHelper () { BOOL _mouseDown; diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index c1856a00..ae7f10c0 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -89,28 +89,24 @@ void ImGui_Marmalade_RenderDrawLists(ImDrawData* draw_data) // TODO: restore modified state (i.e. mvp matrix) } -static const char* ImGui_Marmalade_GetClipboardText() +static const char* ImGui_Marmalade_GetClipboardText(void* /*user_data*/) { - if (s3eClipboardAvailable()) + if (!s3eClipboardAvailable()) + return NULL; + + if (int size = s3eClipboardGetText(NULL, 0)) { - int size = s3eClipboardGetText(NULL, 0); - if (size > 0) - { - if (g_ClipboardText) - { - delete[] g_ClipboardText; - g_ClipboardText = NULL; - } - g_ClipboardText = new char[size]; - g_ClipboardText[0] = '\0'; - s3eClipboardGetText(g_ClipboardText, size); - } + if (g_ClipboardText) + delete[] g_ClipboardText; + g_ClipboardText = new char[size]; + g_ClipboardText[0] = '\0'; + s3eClipboardGetText(g_ClipboardText, size); } return g_ClipboardText; } -static void ImGui_Marmalade_SetClipboardText(const char* text) +static void ImGui_Marmalade_SetClipboardText(void* /*user_data*/, const char* text) { if (s3eClipboardAvailable()) s3eClipboardSetText(text); diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index cd8e60d4..63e9cae0 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -112,14 +112,14 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } -static const char* ImGui_ImplGlfw_GetClipboardText() +static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) { - return glfwGetClipboardString(g_Window); + return glfwGetClipboardString((GLFWwindow*)user_data); } -static void ImGui_ImplGlfw_SetClipboardText(const char* text) +static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) { - glfwSetClipboardString(g_Window, text); + glfwSetClipboardString((GLFWwindow*)user_data, text); } void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) @@ -219,6 +219,7 @@ bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks) io.RenderDrawListsFn = ImGui_ImplGlfw_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + io.ClipboardUserData = g_Window; #ifdef _WIN32 io.ImeWindowHandle = glfwGetWin32Window(g_Window); #endif diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 0cc0cba5..b2040f64 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -129,14 +129,14 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } -static const char* ImGui_ImplGlfwGL3_GetClipboardText() +static const char* ImGui_ImplGlfwGL3_GetClipboardText(void* user_data) { - return glfwGetClipboardString(g_Window); + return glfwGetClipboardString((GLFWwindow*)user_data); } -static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text) +static void ImGui_ImplGlfwGL3_SetClipboardText(void* user_data, const char* text) { - glfwSetClipboardString(g_Window, text); + glfwSetClipboardString((GLFWwindow*)user_data, text); } void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) @@ -329,6 +329,7 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; + io.ClipboardUserData = g_Window; #ifdef _WIN32 io.ImeWindowHandle = glfwGetWin32Window(g_Window); #endif diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp index 01e493d0..b7965253 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp @@ -101,12 +101,12 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } -static const char* ImGui_ImplSdl_GetClipboardText() +static const char* ImGui_ImplSdl_GetClipboardText(void*) { return SDL_GetClipboardText(); } -static void ImGui_ImplSdl_SetClipboardText(const char* text) +static void ImGui_ImplSdl_SetClipboardText(void*, const char* text) { SDL_SetClipboardText(text); } @@ -214,6 +214,7 @@ bool ImGui_ImplSdl_Init(SDL_Window* window) io.RenderDrawListsFn = ImGui_ImplSdl_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.SetClipboardTextFn = ImGui_ImplSdl_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSdl_GetClipboardText; + io.ClipboardUserData = NULL; #ifdef _WIN32 SDL_SysWMinfo wmInfo; diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 4c0e82a0..80db341f 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -123,12 +123,12 @@ void ImGui_ImplSdlGL3_RenderDrawLists(ImDrawData* draw_data) glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); } -static const char* ImGui_ImplSdlGL3_GetClipboardText() +static const char* ImGui_ImplSdlGL3_GetClipboardText(void*) { return SDL_GetClipboardText(); } -static void ImGui_ImplSdlGL3_SetClipboardText(const char* text) +static void ImGui_ImplSdlGL3_SetClipboardText(void*, const char* text) { SDL_SetClipboardText(text); } @@ -327,6 +327,7 @@ bool ImGui_ImplSdlGL3_Init(SDL_Window* window) io.RenderDrawListsFn = ImGui_ImplSdlGL3_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.SetClipboardTextFn = ImGui_ImplSdlGL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSdlGL3_GetClipboardText; + io.ClipboardUserData = NULL; #ifdef _WIN32 SDL_SysWMinfo wmInfo; diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 55260044..5ef2ec5f 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -401,14 +401,14 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) } } -static const char* ImGui_ImplGlfwVulkan_GetClipboardText() +static const char* ImGui_ImplGlfwVulkan_GetClipboardText(void* user_data) { - return glfwGetClipboardString(g_Window); + return glfwGetClipboardString((GLFWwindow*)user_data); } -static void ImGui_ImplGlfwVulkan_SetClipboardText(const char* text) +static void ImGui_ImplGlfwVulkan_SetClipboardText(void* user_data, const char* text) { - glfwSetClipboardString(g_Window, text); + glfwSetClipboardString((GLFWwindow*)user_data, text); } void ImGui_ImplGlfwVulkan_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) @@ -861,6 +861,7 @@ bool ImGui_ImplGlfwVulkan_Init(GLFWwindow* window, bool install_callbacks, Im io.RenderDrawListsFn = ImGui_ImplGlfwVulkan_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.SetClipboardTextFn = ImGui_ImplGlfwVulkan_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplGlfwVulkan_GetClipboardText; + io.ClipboardUserData = g_Window; #ifdef _WIN32 io.ImeWindowHandle = glfwGetWin32Window(g_Window); #endif diff --git a/imgui.cpp b/imgui.cpp index 3bb3241b..db28549d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -150,6 +150,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. @@ -703,8 +704,8 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* ini // Platform dependent default implementations //----------------------------------------------------------------------------- -static const char* GetClipboardTextFn_DefaultImpl(); -static void SetClipboardTextFn_DefaultImpl(const char* text); +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); //----------------------------------------------------------------------------- @@ -829,6 +830,7 @@ ImGuiIO::ImGuiIO() MemFreeFn = free; GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + ClipboardUserData = NULL; ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; // Set OS X style defaults based on __APPLE__ compile time flag @@ -2010,13 +2012,13 @@ void ImGui::MemFree(void* ptr) const char* ImGui::GetClipboardText() { - return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn() : ""; + return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : ""; } void ImGui::SetClipboardText(const char* text) { if (GImGui->IO.SetClipboardTextFn) - GImGui->IO.SetClipboardTextFn(text); + GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text); } const char* ImGui::GetVersion() @@ -5796,8 +5798,7 @@ void ImGui::LogFinish() } if (g.LogClipboard->size() > 1) { - if (g.IO.SetClipboardTextFn) - g.IO.SetClipboardTextFn(g.LogClipboard->begin()); + SetClipboardText(g.LogClipboard->begin()); g.LogClipboard->clear(); } } @@ -7859,7 +7860,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW; edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1); ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie); - io.SetClipboardTextFn(edit_state.TempTextBuffer.Data); + SetClipboardText(edit_state.TempTextBuffer.Data); } if (cut) @@ -7871,7 +7872,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) { // Paste - if (const char* clipboard = io.GetClipboardTextFn ? io.GetClipboardTextFn() : NULL) + if (const char* clipboard = GetClipboardText()) { // Filter pasted buffer const int clipboard_len = (int)strlen(clipboard); @@ -9565,7 +9566,7 @@ void ImGui::ValueColor(const char* prefix, ImU32 v) #pragma comment(lib, "user32") #endif -static const char* GetClipboardTextFn_DefaultImpl() +static const char* GetClipboardTextFn_DefaultImpl(void*) { static ImVector buf_local; buf_local.clear(); @@ -9585,7 +9586,7 @@ static const char* GetClipboardTextFn_DefaultImpl() return buf_local.Data; } -static void SetClipboardTextFn_DefaultImpl(const char* text) +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) { if (!OpenClipboard(NULL)) return; @@ -9604,13 +9605,13 @@ static void SetClipboardTextFn_DefaultImpl(const char* text) #else // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers -static const char* GetClipboardTextFn_DefaultImpl() +static const char* GetClipboardTextFn_DefaultImpl(void*) { return GImGui->PrivateClipboard; } // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers -static void SetClipboardTextFn_DefaultImpl(const char* text) +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) { ImGuiContext& g = *GImGui; if (g.PrivateClipboard) diff --git a/imgui.h b/imgui.h index dad5abaa..edb1d68d 100644 --- a/imgui.h +++ b/imgui.h @@ -757,8 +757,9 @@ struct ImGuiIO // Optional: access OS clipboard // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) - const char* (*GetClipboardTextFn)(); - void (*SetClipboardTextFn)(const char* text); + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; // Optional: override memory allocations. MemFreeFn() may be called with a NULL pointer. // (default to posix malloc/free) From 7252d93dcd2a39db6536073cdb76853fd46d17e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 16 Oct 2016 11:34:33 +0200 Subject: [PATCH 340/400] stb_textedit.h Merged from master 1.9 (merged bits from #473) --- imgui.cpp | 6 +++--- stb_textedit.h | 35 ++++++++++++++++++----------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index db28549d..07466840 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7429,12 +7429,12 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; } -static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } #ifdef __APPLE__ // FIXME: Move setting to IO structure static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; } -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } #else -static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } #endif #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL diff --git a/stb_textedit.h b/stb_textedit.h index 2dddefe4..16441047 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,10 +1,9 @@ -// [ImGui] this is a slightly modified version of stb_truetype.h 1.8 +// [ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715) // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) // [ImGui] - fixed some minor warnings -// [ImGui] - added STB_TEXTEDIT_MOVEWORDLEFT/STB_TEXTEDIT_MOVEWORDRIGHT custom handler (#473) -// stb_textedit.h - v1.8 - public domain - Sean Barrett +// stb_textedit.h - v1.9 - public domain - Sean Barrett // Development of this library was sponsored by RAD Game Tools // // This C header file implements the guts of a multi-line text-editing @@ -37,6 +36,7 @@ // // VERSION HISTORY // +// 1.9 (2016-08-27) customizable move-by-word // 1.8 (2016-04-02) better keyboard handling when mouse button is down // 1.7 (2015-09-13) change y range handling in case baseline is non-0 // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove @@ -425,10 +425,9 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) // check if it's before the end of the line if (x < r.x1) { // search characters in row for one that straddles 'x' - k = i; prev_x = r.x0; - for (i=0; i < r.num_chars; ++i) { - float w = STB_TEXTEDIT_GETWIDTH(str, k, i); + for (k=0; k < r.num_chars; ++k) { + float w = STB_TEXTEDIT_GETWIDTH(str, i, k); if (x < prev_x+w) { if (x < prev_x+w/2) return k+i; @@ -618,15 +617,16 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat } #ifdef STB_TEXTEDIT_IS_SPACE -static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx ) +static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) { - return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1; + return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; } #ifndef STB_TEXTEDIT_MOVEWORDLEFT -static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, int c ) +static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) { - while( c >= 0 && !is_word_boundary( _str, c ) ) + --c; // always move at least one character + while( c >= 0 && !is_word_boundary( str, c ) ) --c; if( c < 0 ) @@ -638,10 +638,11 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, int c #endif #ifndef STB_TEXTEDIT_MOVEWORDRIGHT -static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, int c ) +static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) { - const int len = STB_TEXTEDIT_STRINGLEN(_str); - while( c < len && !is_word_boundary( _str, c ) ) + const int len = STB_TEXTEDIT_STRINGLEN(str); + ++c; // always move at least one character + while( c < len && !is_word_boundary( str, c ) ) ++c; if( c > len ) @@ -778,7 +779,7 @@ retry: if (STB_TEXT_HAS_SELECTION(state)) stb_textedit_move_to_first(state); else { - state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor-1); + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); stb_textedit_clamp( str, state ); } break; @@ -787,7 +788,7 @@ retry: if( !STB_TEXT_HAS_SELECTION( state ) ) stb_textedit_prep_selection_at_cursor(state); - state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor-1); + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); state->select_end = state->cursor; stb_textedit_clamp( str, state ); @@ -799,7 +800,7 @@ retry: if (STB_TEXT_HAS_SELECTION(state)) stb_textedit_move_to_last(str, state); else { - state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor+1); + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); stb_textedit_clamp( str, state ); } break; @@ -808,7 +809,7 @@ retry: if( !STB_TEXT_HAS_SELECTION( state ) ) stb_textedit_prep_selection_at_cursor(state); - state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor+1); + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); state->select_end = state->cursor; stb_textedit_clamp( str, state ); From b3790e7549d5e47c57151d3985d64234f2ba81d8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 16 Oct 2016 13:34:47 +0200 Subject: [PATCH 341/400] InputText: Fixed pressing home key on last character when it isn't a trailing \n (#588, #815) --- stb_textedit.h | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/stb_textedit.h b/stb_textedit.h index 16441047..4b731a0c 100644 --- a/stb_textedit.h +++ b/stb_textedit.h @@ -1,4 +1,5 @@ // [ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb +// [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815) // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715) // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) // [ImGui] - fixed some minor warnings @@ -992,58 +993,58 @@ retry: #ifdef STB_TEXTEDIT_K_LINESTART2 case STB_TEXTEDIT_K_LINESTART2: #endif - case STB_TEXTEDIT_K_LINESTART: { - StbFindState find; + case STB_TEXTEDIT_K_LINESTART: stb_textedit_clamp(str, state); stb_textedit_move_to_first(state); - stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - state->cursor = find.first_char; + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; state->has_preferred_x = 0; break; - } #ifdef STB_TEXTEDIT_K_LINEEND2 case STB_TEXTEDIT_K_LINEEND2: #endif case STB_TEXTEDIT_K_LINEEND: { - StbFindState find; + int n = STB_TEXTEDIT_STRINGLEN(str); stb_textedit_clamp(str, state); stb_textedit_move_to_first(state); - stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) - --state->cursor; break; } #ifdef STB_TEXTEDIT_K_LINESTART2 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: #endif - case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: { - StbFindState find; + case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: stb_textedit_clamp(str, state); stb_textedit_prep_selection_at_cursor(state); - stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - state->cursor = state->select_end = find.first_char; + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->select_end = state->cursor; state->has_preferred_x = 0; break; - } #ifdef STB_TEXTEDIT_K_LINEEND2 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: #endif case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { - StbFindState find; + int n = STB_TEXTEDIT_STRINGLEN(str); stb_textedit_clamp(str, state); stb_textedit_prep_selection_at_cursor(state); - stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); - state->has_preferred_x = 0; - state->cursor = find.first_char + find.length; - if (find.length > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) == STB_TEXTEDIT_NEWLINE) - --state->cursor; + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; state->select_end = state->cursor; + state->has_preferred_x = 0; break; } From 6fa3aaf7c00538c508578295f37801a49edbeb77 Mon Sep 17 00:00:00 2001 From: James Fulop Date: Sun, 16 Oct 2016 12:21:38 -0400 Subject: [PATCH 342/400] outdated dragging API mentioned in demo text Looks like you changed the API on dragging, but did not update the description text for it. https://github.com/ocornut/imgui/issues/167 --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e2ede9bd..544d6230 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1542,7 +1542,7 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("Dragging")) { - ImGui::TextWrapped("You can use ImGui::GetItemActiveDragDelta() to query for the dragged amount on any widget."); + ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); ImGui::Button("Drag Me"); if (ImGui::IsItemActive()) { From 44250caf505124eb1243924419266efb3a5a0146 Mon Sep 17 00:00:00 2001 From: Marcell Kiss Date: Tue, 18 Oct 2016 22:07:51 +0200 Subject: [PATCH 343/400] Null the released resources --- .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 5ef2ec5f..9469e7a8 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -798,31 +798,45 @@ void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects() ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); for (int i=0; i Date: Tue, 18 Oct 2016 22:40:58 +0200 Subject: [PATCH 344/400] Add location decorators & change to use structs as in/out in glsl, update embedded spv (produced with glslangValidator -x) --- examples/vulkan_example/gen_spv.sh | 5 +- examples/vulkan_example/glsl_shader.frag | 4 +- examples/vulkan_example/glsl_shader.vert | 2 +- .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 235 ++++++------------ 4 files changed, 81 insertions(+), 165 deletions(-) diff --git a/examples/vulkan_example/gen_spv.sh b/examples/vulkan_example/gen_spv.sh index f95f8fa8..e0d7f3b0 100755 --- a/examples/vulkan_example/gen_spv.sh +++ b/examples/vulkan_example/gen_spv.sh @@ -1,4 +1,3 @@ #!/bin/bash -glslangValidator -V -o glsl_shader.frag.spv glsl_shader.frag -glslangValidator -V -o glsl_shader.vert.spv glsl_shader.vert -spirv-remap --map all --dce all --strip-all --input glsl_shader.frag.spv glsl_shader.vert.spv --output ./ +glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag +glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert diff --git a/examples/vulkan_example/glsl_shader.frag b/examples/vulkan_example/glsl_shader.frag index 8205b673..313a8880 100644 --- a/examples/vulkan_example/glsl_shader.frag +++ b/examples/vulkan_example/glsl_shader.frag @@ -1,9 +1,9 @@ #version 450 core -layout(location = 0, index = 0) out vec4 fColor; +layout(location = 0) out vec4 fColor; layout(set=0, binding=0) uniform sampler2D sTexture; -in block{ +layout(location = 0) in struct{ vec4 Color; vec2 UV; } In; diff --git a/examples/vulkan_example/glsl_shader.vert b/examples/vulkan_example/glsl_shader.vert index 55098fec..c4e4e216 100644 --- a/examples/vulkan_example/glsl_shader.vert +++ b/examples/vulkan_example/glsl_shader.vert @@ -8,7 +8,7 @@ layout(push_constant) uniform uPushConstant{ vec2 uTranslate; } pc; -out block{ +layout(location = 0) out struct{ vec4 Color; vec2 UV; } Out; diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 9469e7a8..348ab559 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -59,168 +59,85 @@ static VkBuffer g_IndexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; -static unsigned char __glsl_shader_vert_spv[] = +static uint32_t __glsl_shader_vert_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, - 0x6c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, - 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0x16, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x41, 0x14, 0x00, 0x00, - 0x6a, 0x16, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, 0x80, 0x14, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x41, 0x14, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6a, 0x16, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0xb1, 0x02, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0xb1, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0xb1, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0xb1, 0x02, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x80, 0x14, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x06, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x06, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0xfa, 0x16, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x02, 0x05, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, - 0x1a, 0x04, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1a, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, - 0x47, 0x11, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x9a, 0x02, 0x00, 0x00, 0x41, 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x9b, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x0e, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x90, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, 0x6a, 0x16, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x91, 0x02, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x7f, 0x02, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, - 0xb1, 0x02, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x7f, 0x02, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2e, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x05, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, - 0x80, 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, - 0x06, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x83, 0x06, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x06, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x83, 0x06, 0x00, 0x00, - 0xfa, 0x16, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x92, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x36, 0x00, 0x05, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x1f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x05, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x6b, 0x60, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x71, 0x4e, 0x00, 0x00, - 0x41, 0x14, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x9b, 0x02, 0x00, 0x00, - 0xaa, 0x26, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0xaa, 0x26, 0x00, 0x00, 0x71, 0x4e, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xda, 0x35, 0x00, 0x00, - 0x6a, 0x16, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x91, 0x02, 0x00, 0x00, - 0xea, 0x50, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0xea, 0x50, 0x00, 0x00, 0xda, 0x35, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xc7, 0x35, 0x00, 0x00, - 0x80, 0x14, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x92, 0x02, 0x00, 0x00, - 0xef, 0x56, 0x00, 0x00, 0xfa, 0x16, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xe0, 0x29, 0x00, 0x00, - 0xef, 0x56, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xa0, 0x22, 0x00, 0x00, 0xc7, 0x35, 0x00, 0x00, 0xe0, 0x29, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x92, 0x02, 0x00, 0x00, 0x42, 0x2c, 0x00, 0x00, - 0xfa, 0x16, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x42, 0x2c, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, - 0xa0, 0x22, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0xa1, 0x41, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x84, 0x36, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x07, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x47, 0x00, 0x00, - 0xa1, 0x41, 0x00, 0x00, 0x84, 0x36, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, - 0x8a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x9b, 0x02, 0x00, 0x00, - 0x17, 0x2f, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x17, 0x2f, 0x00, 0x00, 0x54, 0x47, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 + 0x07230203,0x00010000,0x00080001,0x00000031,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015, + 0x0000001e,0x0000001f,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43, + 0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f, + 0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005, + 0x0000001c,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x0000001c,0x00000000, + 0x505f6c67,0x7469736f,0x006e6f69,0x00070006,0x0000001c,0x00000001,0x505f6c67,0x746e696f, + 0x657a6953,0x00000000,0x00070006,0x0000001c,0x00000002,0x435f6c67,0x4470696c,0x61747369, + 0x0065636e,0x00070006,0x0000001c,0x00000003,0x435f6c67,0x446c6c75,0x61747369,0x0065636e, + 0x00030005,0x0000001e,0x00000000,0x00040005,0x0000001f,0x736f5061,0x00000000,0x00060005, + 0x00000021,0x73755075,0x6e6f4368,0x6e617473,0x00000074,0x00050006,0x00000021,0x00000000, + 0x61635375,0x0000656c,0x00060006,0x00000021,0x00000001,0x61725475,0x616c736e,0x00006574, + 0x00030005,0x00000023,0x00006370,0x00040047,0x0000000b,0x0000001e,0x00000000,0x00040047, + 0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,0x0000001e,0x00000001,0x00050048, + 0x0000001c,0x00000000,0x0000000b,0x00000000,0x00050048,0x0000001c,0x00000001,0x0000000b, + 0x00000001,0x00050048,0x0000001c,0x00000002,0x0000000b,0x00000003,0x00050048,0x0000001c, + 0x00000003,0x0000000b,0x00000004,0x00030047,0x0000001c,0x00000002,0x00040047,0x0000001f, + 0x0000001e,0x00000000,0x00050048,0x00000021,0x00000000,0x00000023,0x00000000,0x00050048, + 0x00000021,0x00000001,0x00000023,0x00000008,0x00030047,0x00000021,0x00000002,0x00020013, + 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, + 0x00000007,0x00000006,0x00000004,0x00040017,0x00000008,0x00000006,0x00000002,0x0004001e, + 0x00000009,0x00000007,0x00000008,0x00040020,0x0000000a,0x00000003,0x00000009,0x0004003b, + 0x0000000a,0x0000000b,0x00000003,0x00040015,0x0000000c,0x00000020,0x00000001,0x0004002b, + 0x0000000c,0x0000000d,0x00000000,0x00040020,0x0000000e,0x00000001,0x00000007,0x0004003b, + 0x0000000e,0x0000000f,0x00000001,0x00040020,0x00000011,0x00000003,0x00000007,0x0004002b, + 0x0000000c,0x00000013,0x00000001,0x00040020,0x00000014,0x00000001,0x00000008,0x0004003b, + 0x00000014,0x00000015,0x00000001,0x00040020,0x00000017,0x00000003,0x00000008,0x00040015, + 0x00000019,0x00000020,0x00000000,0x0004002b,0x00000019,0x0000001a,0x00000001,0x0004001c, + 0x0000001b,0x00000006,0x0000001a,0x0006001e,0x0000001c,0x00000007,0x00000006,0x0000001b, + 0x0000001b,0x00040020,0x0000001d,0x00000003,0x0000001c,0x0004003b,0x0000001d,0x0000001e, + 0x00000003,0x0004003b,0x00000014,0x0000001f,0x00000001,0x0004001e,0x00000021,0x00000008, + 0x00000008,0x00040020,0x00000022,0x00000009,0x00000021,0x0004003b,0x00000022,0x00000023, + 0x00000009,0x00040020,0x00000024,0x00000009,0x00000008,0x0004002b,0x00000006,0x0000002b, + 0x00000000,0x0004002b,0x00000006,0x0000002c,0x3f800000,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f, + 0x00050041,0x00000011,0x00000012,0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010, + 0x0004003d,0x00000008,0x00000016,0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b, + 0x00000013,0x0003003e,0x00000018,0x00000016,0x0004003d,0x00000008,0x00000020,0x0000001f, + 0x00050041,0x00000024,0x00000025,0x00000023,0x0000000d,0x0004003d,0x00000008,0x00000026, + 0x00000025,0x00050085,0x00000008,0x00000027,0x00000020,0x00000026,0x00050041,0x00000024, + 0x00000028,0x00000023,0x00000013,0x0004003d,0x00000008,0x00000029,0x00000028,0x00050081, + 0x00000008,0x0000002a,0x00000027,0x00000029,0x00050051,0x00000006,0x0000002d,0x0000002a, + 0x00000000,0x00050051,0x00000006,0x0000002e,0x0000002a,0x00000001,0x00070050,0x00000007, + 0x0000002f,0x0000002d,0x0000002e,0x0000002b,0x0000002c,0x00050041,0x00000011,0x00000030, + 0x0000001e,0x0000000d,0x0003003e,0x00000030,0x0000002f,0x000100fd,0x00010038 }; -static unsigned int __glsl_shader_vert_spv_len = 1172; -static unsigned char __glsl_shader_frag_spv[] = +static uint32_t __glsl_shader_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, - 0x6c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x1f, 0x16, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x7a, 0x0c, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, - 0x1f, 0x16, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x7a, 0x0c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x7a, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1a, 0x04, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xec, 0x14, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xec, 0x14, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, - 0x02, 0x05, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, - 0x7a, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x04, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x97, 0x06, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x9b, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x09, 0x00, 0x96, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x03, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x7b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfe, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x7b, 0x04, 0x00, 0x00, - 0xec, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x6b, 0x5d, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x9b, 0x02, 0x00, 0x00, 0x8d, 0x1b, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, - 0x0b, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x0b, 0x40, 0x00, 0x00, 0x8d, 0x1b, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0xfe, 0x01, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00, 0xec, 0x14, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x90, 0x02, 0x00, 0x00, 0xc2, 0x43, 0x00, 0x00, - 0x35, 0x16, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0xc2, 0x43, 0x00, 0x00, - 0x57, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xb9, 0x46, 0x00, 0x00, - 0xc0, 0x36, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0xe4, 0x23, 0x00, 0x00, 0x0b, 0x40, 0x00, 0x00, - 0xb9, 0x46, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7a, 0x0c, 0x00, 0x00, - 0xe4, 0x23, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 + 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010, + 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000, + 0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001, + 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574, + 0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e, + 0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021, + 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, + 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, + 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006, + 0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001, + 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020, + 0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001, + 0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000, + 0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018, + 0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d, + 0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017, + 0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a, + 0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085, + 0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd, + 0x00010038 }; -static unsigned int __glsl_shader_frag_spv_len = 660; static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) { @@ -604,13 +521,13 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() { VkShaderModuleCreateInfo vert_info = {}; vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - vert_info.codeSize = __glsl_shader_vert_spv_len; + vert_info.codeSize = sizeof(__glsl_shader_vert_spv); vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module); ImGui_ImplGlfwVulkan_VkResult(err); VkShaderModuleCreateInfo frag_info = {}; frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - frag_info.codeSize = __glsl_shader_frag_spv_len; + frag_info.codeSize = sizeof(__glsl_shader_frag_spv); frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); ImGui_ImplGlfwVulkan_VkResult(err); From ddf08ec2e846659a298351b6f9d91cf5d641b991 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 15:12:45 +0100 Subject: [PATCH 345/400] BeginChild(const char*) applies stack id to provided label (#894, #713) --- imgui.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 07466840..c143d0b0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -150,6 +150,7 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. @@ -3581,12 +3582,12 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button) return BeginPopup(str_id); } -bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; - const ImVec2 content_avail = GetContentRegionAvail(); + const ImVec2 content_avail = ImGui::GetContentRegionAvail(); ImVec2 size = ImFloor(size_arg); if (size.x <= 0.0f) { @@ -3605,22 +3606,28 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, flags |= extra_flags; char title[256]; - ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s", window->Name, str_id); + if (name) + ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s.%08X", window->Name, name, id); + else + ImFormatString(title, IM_ARRAYSIZE(title), "%s.%08X", window->Name, id); bool ret = ImGui::Begin(title, NULL, size, -1.0f, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) - GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; + ImGui::GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; return ret; } -bool ImGui::BeginChild(ImGuiID id, const ImVec2& size, bool border, ImGuiWindowFlags extra_flags) +bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { - char str_id[32]; - ImFormatString(str_id, IM_ARRAYSIZE(str_id), "child_%08x", id); - bool ret = ImGui::BeginChild(str_id, size, border, extra_flags); - return ret; + ImGuiWindow* window = GetCurrentWindow(); + return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); +} + +bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + return BeginChildEx(NULL, id, size_arg, border, extra_flags); } void ImGui::EndChild() From 907dd2ed2026c2b093dafcf593e66031675e592c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 15:25:28 +0100 Subject: [PATCH 346/400] Comments (#896) --- imgui_draw.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ade41777..7bdb94c7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1942,7 +1942,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons else { s += ImTextCharFromUtf8(&c, s, text_end); - if (c == 0) + if (c == 0) // Malformed UTF-8? break; } @@ -2000,7 +2000,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const { if (!text_end) - text_end = text_begin + strlen(text_begin); + text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls. // Align to be pixel perfect pos.x = (float)(int)pos.x + DisplayOffset.x; @@ -2068,7 +2068,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col else { s += ImTextCharFromUtf8(&c, s, text_end); - if (c == 0) + if (c == 0) // Malformed UTF-8? break; } From 357167f917c3f92bf3fbeb11bf29a304caa50593 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 18:13:14 +0100 Subject: [PATCH 347/400] Demo: Custom Rendering: Tweak so end of line can be dropped outside of canvas, more pleasing. --- imgui_demo.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 544d6230..4ad5e647 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2041,21 +2041,21 @@ static void ShowExampleAppCustomRendering(bool* p_open) bool adding_preview = false; ImGui::InvisibleButton("canvas", canvas_size); + ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); + if (adding_line) + { + adding_preview = true; + points.push_back(mouse_pos_in_canvas); + if (!ImGui::GetIO().MouseDown[0]) + adding_line = adding_preview = false; + } if (ImGui::IsItemHovered()) { - ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); if (!adding_line && ImGui::IsMouseClicked(0)) { points.push_back(mouse_pos_in_canvas); adding_line = true; } - if (adding_line) - { - adding_preview = true; - points.push_back(mouse_pos_in_canvas); - if (!ImGui::GetIO().MouseDown[0]) - adding_line = adding_preview = false; - } if (ImGui::IsMouseClicked(1) && !points.empty()) { adding_line = adding_preview = false; From b376b683263aabc69fa8a6983b93a0238458232f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 21:50:18 +0100 Subject: [PATCH 348/400] Font: Added io.FontDefault in ImGuiIO structure to make it easier to change default font from third-party or demo code --- imgui.cpp | 15 ++++++++++++--- imgui.h | 1 + imgui_demo.cpp | 5 +++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c143d0b0..e7984b9b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -658,6 +658,7 @@ static float GetDraggedColumnOffset(int column_index); static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true); +static ImFont* GetDefaultFont(); static void SetCurrentFont(ImFont* font); static void SetCurrentWindow(ImGuiWindow* window); static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y); @@ -809,6 +810,7 @@ ImGuiIO::ImGuiIO() LogFilename = "imgui_log.txt"; Fonts = &GImDefaultFontAtlas; FontGlobalScale = 1.0f; + FontDefault = NULL; DisplayFramebufferScale = ImVec2(1.0f, 1.0f); MousePos = ImVec2(-1,-1); MousePosPrev = ImVec2(-1,-1); @@ -2106,7 +2108,8 @@ void ImGui::NewFrame() g.Initialized = true; } - SetCurrentFont(g.IO.Fonts->Fonts[0]); + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); g.Time += g.IO.DeltaTime; g.FrameCount += 1; @@ -4586,6 +4589,12 @@ float ImGui::CalcItemWidth() return w; } +static ImFont* GetDefaultFont() +{ + ImGuiContext& g = *GImGui; + return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; +} + static void SetCurrentFont(ImFont* font) { ImGuiContext& g = *GImGui; @@ -4601,7 +4610,7 @@ void ImGui::PushFont(ImFont* font) { ImGuiContext& g = *GImGui; if (!font) - font = g.IO.Fonts->Fonts[0]; + font = GetDefaultFont(); SetCurrentFont(font); g.FontStack.push_back(font); g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); @@ -4612,7 +4621,7 @@ void ImGui::PopFont() ImGuiContext& g = *GImGui; g.CurrentWindow->DrawList->PopTextureID(); g.FontStack.pop_back(); - SetCurrentFont(g.FontStack.empty() ? g.IO.Fonts->Fonts[0] : g.FontStack.back()); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); } void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) diff --git a/imgui.h b/imgui.h index edb1d68d..776b4d5c 100644 --- a/imgui.h +++ b/imgui.h @@ -739,6 +739,7 @@ struct ImGuiIO ImFontAtlas* Fonts; // // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array. float FontGlobalScale; // = 1.0f // Global scale all fonts bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui. ImVec2 DisplayVisibleMin; // (0.0f,0.0f) // If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area. ImVec2 DisplayVisibleMax; // (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4ad5e647..e5215141 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1721,7 +1721,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size)) { ImGui::SameLine(); ShowHelpMarker("Tip: Load fonts with io.Fonts->AddFontFromFileTTF()\nbefore calling io.Fonts->GetTex* functions."); - ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) { ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); @@ -1733,7 +1734,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImFont* font = atlas->Fonts[i]; ImGui::BulletText("Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); ImGui::TreePush((void*)(intptr_t)i); - if (i > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { atlas->Fonts[i] = atlas->Fonts[0]; atlas->Fonts[0] = font; } } + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) io.FontDefault = font; ImGui::PushFont(font); ImGui::Text("The quick brown fox jumps over the lazy dog"); ImGui::PopFont(); From b2f0ea6c0de9869ecc704b659f2805f3d55ee844 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 21:51:20 +0100 Subject: [PATCH 349/400] Font: Default font given explicit name "ProggyClean.ttf" --- imgui_demo.cpp | 5 ++--- imgui_draw.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e5215141..ffc66a93 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1721,8 +1721,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size)) { ImGui::SameLine(); ShowHelpMarker("Tip: Load fonts with io.Fonts->AddFontFromFileTTF()\nbefore calling io.Fonts->GetTex* functions."); - ImGuiIO& io = ImGui::GetIO(); - ImFontAtlas* atlas = io.Fonts; + ImFontAtlas* atlas = ImGui::GetIO().Fonts; if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) { ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); @@ -1734,7 +1733,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImFont* font = atlas->Fonts[i]; ImGui::BulletText("Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); ImGui::TreePush((void*)(intptr_t)i); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) io.FontDefault = font; + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; ImGui::PushFont(font); ImGui::Text("The quick brown fox jumps over the lazy dog"); ImGui::PopFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7bdb94c7..b8b4d9ee 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1184,7 +1184,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) font_cfg.OversampleH = font_cfg.OversampleV = 1; font_cfg.PixelSnapH = true; } - if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, ""); + if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf"); const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, 13.0f, &font_cfg, GetGlyphRangesDefault()); From 84f480a6387b2aa4ed12ae1d65b8ce04c4bb2b72 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 22:21:10 +0100 Subject: [PATCH 350/400] Font: Added Roboto-Medium + tweaked readme --- extra_fonts/README.txt | 13 +++++++++++-- extra_fonts/Roboto-Medium.ttf | Bin 0 -> 162588 bytes 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 extra_fonts/Roboto-Medium.ttf diff --git a/extra_fonts/README.txt b/extra_fonts/README.txt index 1e9bc13c..7ba7b33a 100644 --- a/extra_fonts/README.txt +++ b/extra_fonts/README.txt @@ -94,9 +94,16 @@ FONT FILES INCLUDED IN THIS FOLDER --------------------------------- + Roboto-Medium.ttf + Apache License 2.0 + by Christian Robertson + https://fonts.google.com/specimen/Roboto + Cousine-Regular.ttf + by Steve Matteson Digitized data copyright (c) 2010 Google Corporation. - Licensed under the SIL Open Font License, Version 1.1 + Licensed under the SIL Open Font License, Version 1.1 + https://fonts.google.com/specimen/Cousine DroidSans.ttf Copyright (c) Steve Matteson @@ -107,13 +114,15 @@ Copyright (c) 2004, 2005 Tristan Grimmer MIT License recommended loading setting in ImGui: Size = 13.0, DisplayOffset.Y = +1 + http://www.proggyfonts.net/ ProggyTiny.ttf Copyright (c) 2004, 2005 Tristan Grimmer MIT License recommended loading setting in ImGui: Size = 10.0, DisplayOffset.Y = +1 + http://www.proggyfonts.net/ - Karla-Regular + Karla-Regular.ttf Copyright (c) 2012, Jonathan Pinhorn SIL OPEN FONT LICENSE Version 1.1 diff --git a/extra_fonts/Roboto-Medium.ttf b/extra_fonts/Roboto-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..39c63d7461796094c0b8889ee8fe2706d344a99a GIT binary patch literal 162588 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 cASb?` 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

  • 2a-ytx-(Y1%*Q`;e(V?9Smc22g?_xG~I&%zq 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≀A#j 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%0AHUW;|^l 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 XDz@2YO+x)8BOh4hv Date: Sun, 6 Nov 2016 22:21:21 +0100 Subject: [PATCH 351/400] Font: Font name include size --- imgui_draw.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b8b4d9ee..a6074801 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1184,7 +1184,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) font_cfg.OversampleH = font_cfg.OversampleV = 1; font_cfg.PixelSnapH = true; } - if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf"); + if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px"); const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, 13.0f, &font_cfg, GetGlyphRangesDefault()); @@ -1206,7 +1206,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, // Store a short copy of filename into into the font name for convenience const char* p; for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} - snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p); + snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); } return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges); } From da9feba539f1a45ceaa0140b2d6aa1cbe5625554 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 22:40:47 +0100 Subject: [PATCH 352/400] Fixed missing frame padding on title bar text when Collapse triangle is disabled --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e7984b9b..2d417efa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4327,8 +4327,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us ImVec2 text_max = window->Pos + ImVec2(window->Size.x, style.FramePadding.y*2 + text_size.y); ImRect clip_rect; clip_rect.Max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton() - float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : 0.0f; - float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : 0.0f; + float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x; + float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x; if (style.WindowTitleAlign.x > 0.0f) pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); text_min.x += pad_left; text_max.x -= pad_right; From 3689efb7265fd43b55f37f1e58163a2d98f740c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 6 Nov 2016 22:53:36 +0100 Subject: [PATCH 353/400] Font: Readme about icons --- README.md | 1 + extra_fonts/README.txt | 25 ++++++++++++++++++++----- imgui.cpp | 11 ++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 88b9baeb..ab61f747 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ The library started its life and is best known as "ImGui" only due to the fact t
    How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs.
    How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
    How can I load a different font than the default? +
    How can I easily use icons in my application?
    How can I load multiple fonts?
    How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
    How can I use the drawing facilities without an ImGui window? (using ImDrawList API) diff --git a/extra_fonts/README.txt b/extra_fonts/README.txt index 7ba7b33a..60d33e2e 100644 --- a/extra_fonts/README.txt +++ b/extra_fonts/README.txt @@ -4,12 +4,27 @@ Fonts are rasterized in a single texture at the time of calling either of io.Fonts.GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). - If you want to use icons in ImGui, a good idea is to merge an icon font within your main font, and refer to icons directly in your strings. - You can use headers files with definitions for popular icon fonts codepoints, by Juliette Foucaut, at https://github.com/juliettef/IconFontCppHeaders +--------------------------------- + USING ICONS +--------------------------------- + Using an icon font (such as FontAwesome: http://fontawesome.io) is an easy and practical way to use icons in your ImGui application. + A common pattern is to merge the icon font within your main font, so you can refer to the icons directly from your strings without having to change fonts back and forth. + To refer to the icon from your C++ code, you can use headers files created by Juliette Foucaut, at https://github.com/juliettef/IconFontCppHeaders + + // Merge icons into default tool font + #include "IconsFontAwesome.h" + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->AddFontDefault(); + ImFontConfig config; + config.MergeMode = true; + const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges); + // Usage, e.g. + ImGui::Text("%s Search", ICON_FA_SEARCH); --------------------------------- - LOADING INSTRUCTIONS + FONTS LOADING INSTRUCTIONS --------------------------------- Load default font with: @@ -69,7 +84,7 @@ --------------------------------- - REMAP CODEPOINTS + REMAPPING CODEPOINTS --------------------------------- All your strings needs to use UTF-8 encoding. Specifying literal in your source code using a local code page (such as CP-923 for Japanese CP-1251 for Cyrillic) will not work. @@ -78,7 +93,7 @@ --------------------------------- - EMBED A FONT IN SOURCE CODE + EMBEDDING FONT IN SOURCE CODE --------------------------------- Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array. Then load the font with: diff --git a/imgui.cpp b/imgui.cpp index 2d417efa..bb962306 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -25,6 +25,7 @@ - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs. - How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application? - How can I load a different font than the default? + - How can I easily use icons in my application? - How can I load multiple fonts? - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) @@ -406,6 +407,10 @@ io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() + Q: How can I easily use icons in my application? + A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your strings. + Read 'How can I load multiple fonts?' and the file 'extra_fonts/README.txt' for instructions. + Q: How can I load multiple fonts? A: Use the font atlas to pack them into a single texture: (Read extra_fonts/README.txt and the code in ImFontAtlas for more details.) @@ -425,13 +430,13 @@ config.GlyphExtraSpacing.x = 1.0f; io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config); - // Combine multiple fonts into one + // Combine multiple fonts into one (e.g. for icon fonts) ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; ImFontConfig config; config.MergeMode = true; io.Fonts->AddFontDefault(); - io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); - io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); + io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font + io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. From faafcf418d88a5e2730e98d2efc5948e2e90fce1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Nov 2016 17:33:46 +0100 Subject: [PATCH 354/400] Demo: Comments, even though nobody appears to read the comments. --- imgui_demo.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ffc66a93..9263673c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1804,6 +1804,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::PopItemWidth(); } +// Demonstrate creating a fullscreen menu bar and populating it. static void ShowExampleAppMainMenuBar() { if (ImGui::BeginMainMenuBar()) @@ -1882,6 +1883,7 @@ static void ShowExampleMenuFile() if (ImGui::MenuItem("Quit", "Alt+F4")) {} } +// Demonstrate creating a window which gets auto-resized according to its content. static void ShowExampleAppAutoResize(bool* p_open) { if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) @@ -1898,6 +1900,7 @@ static void ShowExampleAppAutoResize(bool* p_open) ImGui::End(); } +// Demonstrate creating a window with custom resize constraints. static void ShowExampleAppConstrainedResize(bool* p_open) { struct CustomConstraints // Helper functions to demonstrate programmatic constraints @@ -1935,6 +1938,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open) ImGui::End(); } +// Demonstrate creating a simple static window with no decoration. static void ShowExampleAppFixedOverlay(bool* p_open) { ImGui::SetNextWindowPos(ImVec2(10,10)); @@ -1949,10 +1953,12 @@ static void ShowExampleAppFixedOverlay(bool* p_open) ImGui::End(); } +// Demonstrate using "##" and "###" in identifiers to manipulate ID generation. +// Read section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." about ID. static void ShowExampleAppManipulatingWindowTitle(bool*) { // By default, Windows are uniquely identified by their title. - // You can use the "##" and "###" markers to manipulate the display/ID. Read FAQ at the top of this file! + // You can use the "##" and "###" markers to manipulate the display/ID. // Using "##" to display same title but have unique identifier. ImGui::SetNextWindowPos(ImVec2(100,100), ImGuiSetCond_FirstUseEver); @@ -1974,6 +1980,7 @@ static void ShowExampleAppManipulatingWindowTitle(bool*) ImGui::End(); } +// Demonstrate using the low-level ImDrawList to draw custom shapes. static void ShowExampleAppCustomRendering(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(350,560), ImGuiSetCond_FirstUseEver); @@ -2073,6 +2080,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::End(); } +// Demonstrating creating a simple console window, with scrolling, filtering, completion and history. // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. struct ExampleAppConsole { @@ -2422,6 +2430,7 @@ struct ExampleAppLog } }; +// Demonstrate creating a simple log window with basic filtering. static void ShowExampleAppLog(bool* p_open) { static ExampleAppLog log; @@ -2439,6 +2448,7 @@ static void ShowExampleAppLog(bool* p_open) log.Draw("Example: Log", p_open); } +// Demonstrate create a window with multiple child windows. static void ShowExampleAppLayout(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiSetCond_FirstUseEver); @@ -2484,6 +2494,7 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::End(); } +// Demonstrate create a simple property editor. static void ShowExampleAppPropertyEditor(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiSetCond_FirstUseEver); @@ -2556,6 +2567,7 @@ static void ShowExampleAppPropertyEditor(bool* p_open) ImGui::End(); } +// Demonstrate/test rendering huge amount of text, and the incidence of clipping. static void ShowExampleAppLongText(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); From 833ed760aee0f157dc37b1259b96d3c0cb71c806 Mon Sep 17 00:00:00 2001 From: sushitao Date: Wed, 9 Nov 2016 14:53:23 +0800 Subject: [PATCH 355/400] update cmdline syntax in windows compilation --- examples/sdl_opengl2_example/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sdl_opengl2_example/README.md b/examples/sdl_opengl2_example/README.md index aada45d6..deae3239 100644 --- a/examples/sdl_opengl2_example/README.md +++ b/examples/sdl_opengl2_example/README.md @@ -5,7 +5,7 @@ ``` set SDL2DIR=path_to_your_sdl2_folder -cl /Zi /MD /I %SDL2DIR%\include> /I ..\.. main.cpp imgui_impl_sdl.cpp ..\..\imgui*.cpp /link /LIBPATH:%SDL2DIR%\lib SDL2.lib SDL2main.lib +cl /Zi /MD /I %SDL2DIR%\include /I ..\.. main.cpp imgui_impl_sdl.cpp ..\..\imgui*.cpp /link /LIBPATH:%SDL2DIR%\lib SDL2.lib SDL2main.lib opengl32.lib /subsystem:console ``` - On Linux and similar Unixes From 81eefb704b6427bc4758cc55b15f5db845d6c5f6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Nov 2016 18:40:13 +0100 Subject: [PATCH 356/400] Minor const fixes for overzealous warnings (#883) --- examples/opengl2_example/imgui_impl_glfw.cpp | 6 +++--- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index 63e9cae0..a81fac72 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -76,9 +76,9 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); - glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index b2040f64..ffefe758 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -90,10 +90,10 @@ void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) const ImDrawIdx* idx_buffer_offset = 0; glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); - glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { From 8553bab241a62fd7e473b273cf8a9662c9dec2e6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Nov 2016 20:17:35 +0100 Subject: [PATCH 357/400] Ignoring overzealous GCC warnings (#883) --- imgui.cpp | 1 + imgui_demo.cpp | 1 + imgui_draw.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index bb962306..28e1c4c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -650,6 +650,7 @@ #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers #endif //------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9263673c..ba624b2a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -38,6 +38,7 @@ #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement #endif // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a6074801..a660e30c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -46,6 +46,7 @@ #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers #endif //------------------------------------------------------------------------- From 379533f66137f27b1798ce8519981c8a8c51838d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Nov 2016 20:19:07 +0100 Subject: [PATCH 358/400] Updated stb_truetype.h, stb_rect_pack.h primarily to reduce warnings (#883) --- stb_rect_pack.h | 34 +++++++++------ stb_truetype.h | 110 +++++++++++++++++++++++++++++------------------- 2 files changed, 89 insertions(+), 55 deletions(-) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index fafd8897..c75527da 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -1,4 +1,4 @@ -// stb_rect_pack.h - v0.08 - public domain - rectangle packing +// stb_rect_pack.h - v0.10 - public domain - rectangle packing // Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. @@ -32,6 +32,8 @@ // // Version history: // +// 0.10 (2016-10-25) remove cast-away-const to avoid warnings +// 0.09 (2016-08-27) fix compiler warnings // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort @@ -41,9 +43,9 @@ // // LICENSE // -// This software is in the public domain. Where that dedication is not -// recognized, you are granted a perpetual, irrevocable license to copy, -// distribute, and modify this file as you see fit. +// This software is dual-licensed to the public domain and under the following +// license: you are granted a perpetual, irrevocable license to copy, modify, +// publish, and distribute this file as you see fit. ////////////////////////////////////////////////////////////////////////////// // @@ -198,6 +200,12 @@ struct stbrp_context #define STBRP_ASSERT assert #endif +#ifdef _MSC_VER +#define STBRP__NOTUSED(v) (void)(v) +#else +#define STBRP__NOTUSED(v) (void)sizeof(v) +#endif + enum { STBRP__INIT_skyline = 1 @@ -268,12 +276,14 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, } // find minimum y position if it starts at x1 -static int stbrp__skyline_find_min_y(stbrp_context *, stbrp_node *first, int x0, int width, int *pwaste) +static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) { - //(void)c; stbrp_node *node = first; int x1 = x0 + width; int min_y, visited_width, waste_area; + + STBRP__NOTUSED(c); + STBRP_ASSERT(first->x <= x0); #if 0 @@ -501,8 +511,8 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i static int rect_height_compare(const void *a, const void *b) { - stbrp_rect *p = (stbrp_rect *) a; - stbrp_rect *q = (stbrp_rect *) b; + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; if (p->h > q->h) return -1; if (p->h < q->h) @@ -512,8 +522,8 @@ static int rect_height_compare(const void *a, const void *b) static int rect_width_compare(const void *a, const void *b) { - stbrp_rect *p = (stbrp_rect *) a; - stbrp_rect *q = (stbrp_rect *) b; + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; if (p->w > q->w) return -1; if (p->w < q->w) @@ -523,8 +533,8 @@ static int rect_width_compare(const void *a, const void *b) static int rect_original_order(const void *a, const void *b) { - stbrp_rect *p = (stbrp_rect *) a; - stbrp_rect *q = (stbrp_rect *) b; + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); } diff --git a/stb_truetype.h b/stb_truetype.h index e6dae975..88a2da16 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,5 +1,5 @@ -// stb_truetype.h - v1.10 - public domain -// authored from 2009-2015 by Sean Barrett / RAD Game Tools +// stb_truetype.h - v1.12 - public domain +// authored from 2009-2016 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: // parse files @@ -51,6 +51,8 @@ // // VERSION HISTORY // +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning // 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef // 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly // 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges @@ -59,12 +61,6 @@ // fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); // fixed an assert() bug in the new rasterizer // replace assert() with STBTT_assert() in new rasterizer -// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) -// also more precise AA rasterizer, except if shapes overlap -// remove need for STBTT_sort -// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC -// 1.04 (2015-04-15) typo in example -// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes // // Full history can be found at the end of this file. // @@ -592,9 +588,9 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, stbtt_aligned_quad *q, // output: quad to draw int align_to_integer); -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); // Calling these functions in sequence is roughly equivalent to calling // stbtt_PackFontRanges(). If you more control over the packing of multiple // fonts, or if you want to pack custom data into a font texture, take a look @@ -949,6 +945,12 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS #define STBTT_RASTERIZER_VERSION 2 #endif +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + ////////////////////////////////////////////////////////////////////////// // // accessors to parse data from file @@ -961,26 +963,15 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS #define ttCHAR(p) (* (stbtt_int8 *) (p)) #define ttFixed(p) ttLONG(p) -#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE) - - #define ttUSHORT(p) (* (stbtt_uint16 *) (p)) - #define ttSHORT(p) (* (stbtt_int16 *) (p)) - #define ttULONG(p) (* (stbtt_uint32 *) (p)) - #define ttLONG(p) (* (stbtt_int32 *) (p)) - -#else - - static stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; } - static stbtt_int16 ttSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; } - static stbtt_uint32 ttULONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - static stbtt_int32 ttLONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#endif +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } #define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) #define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) -static int stbtt__isfont(const stbtt_uint8 *font) +static int stbtt__isfont(stbtt_uint8 *font) { // check the version number if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 @@ -1004,7 +995,7 @@ static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, return 0; } -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index) +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) { // if it's just a font, there's only one valid index if (stbtt__isfont(font_collection)) @@ -1023,9 +1014,8 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, return -1; } -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart) +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) { - stbtt_uint8 *data = (stbtt_uint8 *) data2; stbtt_uint32 cmap, t; stbtt_int32 i,numTables; @@ -2073,12 +2063,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, // directly AA rasterize edges w/o supersampling static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) { - (void)vsubsample; stbtt__hheap hh = { 0, 0, 0 }; stbtt__active_edge *active = NULL; int y,j=0, i; float scanline_data[129], *scanline, *scanline2; + STBTT__NOTUSED(vsubsample); + if (result->w > 64) scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); else @@ -2524,7 +2515,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned ch // // This is SUPER-CRAPPY packing to keep source code small -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) float pixel_height, // height of font in pixels unsigned char *pixels, int pw, int ph, // bitmap to be filled in int first_char, int num_chars, // characters to bake @@ -2597,11 +2588,6 @@ STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int // #ifndef STB_RECT_PACK_VERSION -#ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) -#else -#define STBTT__NOTUSED(v) (void)sizeof(v) -#endif typedef int stbrp_coord; @@ -2859,7 +2845,7 @@ static float stbtt__oversample_shift(int oversample) } // rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { int i,j,k; @@ -2888,7 +2874,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fon } // rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) { int i,j,k, return_value = 1; @@ -3057,7 +3043,7 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, i // // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) { stbtt_int32 i=0; @@ -3096,9 +3082,9 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 return i; } -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) { - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2); + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); } // returns results in whatever encoding you request... but note that 2-byte encodings @@ -3154,7 +3140,7 @@ static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, return 1; } else if (matchlen < nlen && name[matchlen] == ' ') { ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) return 1; } } else { @@ -3200,7 +3186,7 @@ static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *nam return 0; } -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags) +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) { stbtt_int32 i; for (i=0;;++i) { @@ -3211,11 +3197,49 @@ STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const } } +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + #endif // STB_TRUETYPE_IMPLEMENTATION // FULL VERSION HISTORY // +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning // 1.10 (2016-04-02) allow user-defined fabs() replacement // fix memory leak if fontsize=0.0 // fix warning from duplicate typedef From 775ac24d45fe8ebc3b9dccc683e2bce05c916c85 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 11:14:31 +0100 Subject: [PATCH 359/400] Fixed overzealous GCC warnings (#883) + partly undo 8553bab241a62fd7e473b273cf8a9662c9dec2e6 --- examples/opengl2_example/imgui_impl_glfw.cpp | 6 +++--- examples/sdl_opengl2_example/imgui_impl_sdl.cpp | 6 +++--- imgui_demo.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index a81fac72..3755c608 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -76,9 +76,9 @@ void ImGui_ImplGlfw_RenderDrawLists(ImDrawData* draw_data) const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); - glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp index b7965253..7be0fcdb 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp @@ -65,9 +65,9 @@ void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data) const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); - glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)((char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); + glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, pos))); + glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, uv))); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + OFFSETOF(ImDrawVert, col))); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ba624b2a..f8fc8d11 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -38,7 +38,7 @@ #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement +//#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on github. #endif // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. From a68ac96bc4b37ce79588aec23df83ede0d2f6099 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 12:48:33 +0100 Subject: [PATCH 360/400] Examples: GL3: Comments about gl3w (#880) --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 2 +- examples/opengl3_example/main.cpp | 2 +- examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp | 2 +- examples/sdl_opengl3_example/main.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index ffefe758..97a125d8 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -10,7 +10,7 @@ #include "imgui_impl_glfw_gl3.h" // GL3W/GLFW -#include +#include // This example is using gl3w to access OpenGL functions (because it is small). You may use glew/glad/glLoadGen/etc. whatever already works for you. #include #ifdef _WIN32 #undef APIENTRY diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index fb06b2a2..074bab54 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -4,7 +4,7 @@ #include #include "imgui_impl_glfw_gl3.h" #include -#include +#include // This example is using gl3w to access OpenGL functions (because it is small). You may use glew/glad/glLoadGen/etc. whatever already works for you. #include static void error_callback(int error, const char* description) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 80db341f..9acbf881 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -12,7 +12,7 @@ // SDL,GL3W #include #include -#include +#include // This example is using gl3w to access OpenGL functions (because it is small). You may use glew/glad/glLoadGen/etc. whatever already works for you. // Data static double g_Time = 0.0f; diff --git a/examples/sdl_opengl3_example/main.cpp b/examples/sdl_opengl3_example/main.cpp index 94ef6594..c396405f 100644 --- a/examples/sdl_opengl3_example/main.cpp +++ b/examples/sdl_opengl3_example/main.cpp @@ -4,7 +4,7 @@ #include #include "imgui_impl_sdl_gl3.h" #include -#include +#include // This example is using gl3w to access OpenGL functions (because it is small). You may use glew/glad/glLoadGen/etc. whatever already works for you. #include int main(int, char**) From e0aef0018fb4c47940ced473b55392148ba18339 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 16:08:26 +0100 Subject: [PATCH 361/400] Updated README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab61f747..ae915fc8 100644 --- a/README.md +++ b/README.md @@ -174,12 +174,13 @@ Double-chocolate sponsors: - Media Molecule - Mobigame - Insomniac Games (sponsored the gamepad/keyboard navigation branch) +- Aras Pranckevičius Salty caramel supporters: -- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko. +- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Recognition Robotics, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko. Caramel supporters: -- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, [Kit framework](http://svkonsult.se/kit), Josh Faust, Martin Donlon. +- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, [Kit framework](http://svkonsult.se/kit), Josh Faust, Martin Donlon, Quinton, Felix. And other supporters; thanks! From 98e1d500d4ca3fe6ac025e50f35a0ae29a48d6fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 17:08:31 +0100 Subject: [PATCH 362/400] Support for #define-ing GImGui and IMGUI_SET_CURRENT_CONTEXT_FUNC to enable custom thread-based hackery (#586) --- imgui.cpp | 19 ++++++++++++++----- imgui_internal.h | 4 +++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 28e1c4c3..75c83fdb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -720,14 +720,19 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); // Context //----------------------------------------------------------------------------- -// Default context, default font atlas. +// Default font atlas storage . // New contexts always point by default to this font atlas. It can be changed by reassigning the GetIO().Fonts variable. -static ImGuiContext GImDefaultContext; static ImFontAtlas GImDefaultFontAtlas; -// Current context pointer. Implicitely used by all ImGui functions. Always assumed to be != NULL. Change to a different context by calling ImGui::SetCurrentContext() -// ImGui is currently not thread-safe because of this variable. If you want thread-safety to allow N threads to access N different contexts, you might work around it by (A) having two instances of the ImGui code under different namespaces or (B) change this variable to be TLS. Further development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// Default context storage + current context pointer. +// Implicitely used by all ImGui functions. Always assumed to be != NULL. Change to a different context by calling ImGui::SetCurrentContext() +// ImGui is currently not thread-safe because of this variable. If you want thread-safety to allow N threads to access N different contexts, you might work around it by: +// - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts) +// - or: Changing this variable to be TLS. You may #define GImGui in imconfig.h for further custom hackery. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +#ifndef GImGui +static ImGuiContext GImDefaultContext; ImGuiContext* GImGui = &GImDefaultContext; +#endif //----------------------------------------------------------------------------- // User facing structures @@ -2044,7 +2049,11 @@ ImGuiContext* ImGui::GetCurrentContext() void ImGui::SetCurrentContext(ImGuiContext* ctx) { +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else GImGui = ctx; +#endif } ImGuiContext* ImGui::CreateContext(void* (*malloc_fn)(size_t), void (*free_fn)(void*)) @@ -2063,7 +2072,7 @@ void ImGui::DestroyContext(ImGuiContext* ctx) ctx->~ImGuiContext(); free_fn(ctx); if (GImGui == ctx) - GImGui = NULL; + SetCurrentContext(NULL); } ImGuiIO& ImGui::GetIO() diff --git a/imgui_internal.h b/imgui_internal.h index 08f206ad..39597378 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -67,7 +67,9 @@ namespace ImGuiStb // Context //----------------------------------------------------------------------------- -extern IMGUI_API ImGuiContext* GImGui; // current implicit ImGui context pointer +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer +#endif //----------------------------------------------------------------------------- // Helpers From 55863dd274cc4b9deff3ff5e2cbcf021f90580cf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 17:49:59 +0100 Subject: [PATCH 363/400] Examples: Vulkan: Shallow stylistic changes (following #879) --- .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 54 ++++++------------- .../vulkan_example/imgui_impl_glfw_vulkan.h | 2 + examples/vulkan_example/main.cpp | 10 ++-- 3 files changed, 23 insertions(+), 43 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 348ab559..838e75e9 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -1,4 +1,6 @@ // ImGui GLFW binding with Vulkan + shaders +// FIXME: Changes of ImTextureID aren't supported by this binding! Please, someone add it! + // 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 5 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXX_CreateFontsTexture(), ImGui_ImplXXXX_NewFrame(), ImGui_ImplXXXX_Render() and ImGui_ImplXXXX_Shutdown(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. @@ -713,47 +715,22 @@ void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects() void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects() { ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); - for (int i=0; i Date: Sat, 12 Nov 2016 19:46:52 +0100 Subject: [PATCH 364/400] Examples: DirectX9-10-11: Only call Windows' SetCursor(NULL) when io.MouseDrawCursor is set (#585, #909) --- examples/directx10_example/imgui_impl_dx10.cpp | 3 ++- examples/directx11_example/imgui_impl_dx11.cpp | 3 ++- examples/directx9_example/imgui_impl_dx9.cpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index c604df04..5bda68df 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -573,7 +573,8 @@ void ImGui_ImplDX10_NewFrame() // io.MouseWheel : filled by WM_MOUSEWHEEL events // Hide OS mouse cursor if ImGui is drawing it - SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW)); + if (io.MouseDrawCursor) + SetCursor(NULL); // Start the frame ImGui::NewFrame(); diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index b7da6e06..0a3722eb 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -576,7 +576,8 @@ void ImGui_ImplDX11_NewFrame() // io.MouseWheel : filled by WM_MOUSEWHEEL events // Hide OS mouse cursor if ImGui is drawing it - SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW)); + if (io.MouseDrawCursor) + SetCursor(NULL); // Start the frame ImGui::NewFrame(); diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index b009de75..82e638ef 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -339,7 +339,8 @@ void ImGui_ImplDX9_NewFrame() // io.MouseWheel : filled by WM_MOUSEWHEEL events // Hide OS mouse cursor if ImGui is drawing it - SetCursor(io.MouseDrawCursor ? NULL : LoadCursor(NULL, IDC_ARROW)); + if (io.MouseDrawCursor) + SetCursor(NULL); // Start the frame ImGui::NewFrame(); From fdbad2708c28d2f9e2560e788b8b02dc8be3e91d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 21:04:55 +0100 Subject: [PATCH 365/400] Ignore GCC 6 warnings (#883) --- imgui_demo.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f8fc8d11..e30a004e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -38,7 +38,9 @@ #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure) #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -//#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on github. +#if (__GNUC__ >= 6) +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on github. +#endif #endif // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n. From 1a0e414d3a8a27ec4453d689eb6530f94fac6ad3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 12 Nov 2016 21:17:30 +0100 Subject: [PATCH 366/400] Fixed uninitialized variables (wouldn't have a real effect because they'd be cleared in Begin()). --- imgui_internal.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 39597378..5d358253 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -490,9 +490,11 @@ struct ImGuiContext SetNextWindowSizeCond = 0; SetNextWindowContentSizeCond = 0; SetNextWindowCollapsedCond = 0; - SetNextWindowFocus = false; + SetNextWindowSizeConstraintRect = ImRect(); SetNextWindowSizeConstraintCallback = NULL; SetNextWindowSizeConstraintCallbackUserData = NULL; + SetNextWindowSizeConstraint = false; + SetNextWindowFocus = false; SetNextTreeNodeOpenVal = false; SetNextTreeNodeOpenCond = 0; @@ -599,6 +601,7 @@ struct IMGUI_API ImGuiDrawContext memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); IndentX = 0.0f; + GroupOffsetX = 0.0f; ColumnsOffsetX = 0.0f; ColumnsCurrent = 0; ColumnsCount = 1; From 08ef9819c8b6e7fa21f5acccc57a4e6692b1dcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Sun, 13 Nov 2016 03:00:36 +0100 Subject: [PATCH 367/400] Vulkan example: Fix validation layer warnings and errors and redeclare gl_PerVertex. --- examples/vulkan_example/glsl_shader.vert | 4 + .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 83 +++++++++---------- examples/vulkan_example/main.cpp | 44 +++++++++- 3 files changed, 82 insertions(+), 49 deletions(-) diff --git a/examples/vulkan_example/glsl_shader.vert b/examples/vulkan_example/glsl_shader.vert index c4e4e216..20b29082 100644 --- a/examples/vulkan_example/glsl_shader.vert +++ b/examples/vulkan_example/glsl_shader.vert @@ -8,6 +8,10 @@ layout(push_constant) uniform uPushConstant{ vec2 uTranslate; } pc; +out gl_PerVertex{ + vec4 gl_Position; +}; + layout(location = 0) out struct{ vec4 Color; vec2 UV; diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 838e75e9..ef9da895 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -61,58 +61,52 @@ static VkBuffer g_IndexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; -static uint32_t __glsl_shader_vert_spv[] = +static uint32_t __glsl_shader_vert_spv[] = { - 0x07230203,0x00010000,0x00080001,0x00000031,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b, 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015, - 0x0000001e,0x0000001f,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, 0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43, 0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f, 0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005, - 0x0000001c,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x0000001c,0x00000000, - 0x505f6c67,0x7469736f,0x006e6f69,0x00070006,0x0000001c,0x00000001,0x505f6c67,0x746e696f, - 0x657a6953,0x00000000,0x00070006,0x0000001c,0x00000002,0x435f6c67,0x4470696c,0x61747369, - 0x0065636e,0x00070006,0x0000001c,0x00000003,0x435f6c67,0x446c6c75,0x61747369,0x0065636e, - 0x00030005,0x0000001e,0x00000000,0x00040005,0x0000001f,0x736f5061,0x00000000,0x00060005, - 0x00000021,0x73755075,0x6e6f4368,0x6e617473,0x00000074,0x00050006,0x00000021,0x00000000, - 0x61635375,0x0000656c,0x00060006,0x00000021,0x00000001,0x61725475,0x616c736e,0x00006574, - 0x00030005,0x00000023,0x00006370,0x00040047,0x0000000b,0x0000001e,0x00000000,0x00040047, - 0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,0x0000001e,0x00000001,0x00050048, - 0x0000001c,0x00000000,0x0000000b,0x00000000,0x00050048,0x0000001c,0x00000001,0x0000000b, - 0x00000001,0x00050048,0x0000001c,0x00000002,0x0000000b,0x00000003,0x00050048,0x0000001c, - 0x00000003,0x0000000b,0x00000004,0x00030047,0x0000001c,0x00000002,0x00040047,0x0000001f, - 0x0000001e,0x00000000,0x00050048,0x00000021,0x00000000,0x00000023,0x00000000,0x00050048, - 0x00000021,0x00000001,0x00000023,0x00000008,0x00030047,0x00000021,0x00000002,0x00020013, - 0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017, - 0x00000007,0x00000006,0x00000004,0x00040017,0x00000008,0x00000006,0x00000002,0x0004001e, - 0x00000009,0x00000007,0x00000008,0x00040020,0x0000000a,0x00000003,0x00000009,0x0004003b, - 0x0000000a,0x0000000b,0x00000003,0x00040015,0x0000000c,0x00000020,0x00000001,0x0004002b, - 0x0000000c,0x0000000d,0x00000000,0x00040020,0x0000000e,0x00000001,0x00000007,0x0004003b, - 0x0000000e,0x0000000f,0x00000001,0x00040020,0x00000011,0x00000003,0x00000007,0x0004002b, - 0x0000000c,0x00000013,0x00000001,0x00040020,0x00000014,0x00000001,0x00000008,0x0004003b, - 0x00000014,0x00000015,0x00000001,0x00040020,0x00000017,0x00000003,0x00000008,0x00040015, - 0x00000019,0x00000020,0x00000000,0x0004002b,0x00000019,0x0000001a,0x00000001,0x0004001c, - 0x0000001b,0x00000006,0x0000001a,0x0006001e,0x0000001c,0x00000007,0x00000006,0x0000001b, - 0x0000001b,0x00040020,0x0000001d,0x00000003,0x0000001c,0x0004003b,0x0000001d,0x0000001e, - 0x00000003,0x0004003b,0x00000014,0x0000001f,0x00000001,0x0004001e,0x00000021,0x00000008, - 0x00000008,0x00040020,0x00000022,0x00000009,0x00000021,0x0004003b,0x00000022,0x00000023, - 0x00000009,0x00040020,0x00000024,0x00000009,0x00000008,0x0004002b,0x00000006,0x0000002b, - 0x00000000,0x0004002b,0x00000006,0x0000002c,0x3f800000,0x00050036,0x00000002,0x00000004, - 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f, - 0x00050041,0x00000011,0x00000012,0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010, - 0x0004003d,0x00000008,0x00000016,0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b, - 0x00000013,0x0003003e,0x00000018,0x00000016,0x0004003d,0x00000008,0x00000020,0x0000001f, - 0x00050041,0x00000024,0x00000025,0x00000023,0x0000000d,0x0004003d,0x00000008,0x00000026, - 0x00000025,0x00050085,0x00000008,0x00000027,0x00000020,0x00000026,0x00050041,0x00000024, - 0x00000028,0x00000023,0x00000013,0x0004003d,0x00000008,0x00000029,0x00000028,0x00050081, - 0x00000008,0x0000002a,0x00000027,0x00000029,0x00050051,0x00000006,0x0000002d,0x0000002a, - 0x00000000,0x00050051,0x00000006,0x0000002e,0x0000002a,0x00000001,0x00070050,0x00000007, - 0x0000002f,0x0000002d,0x0000002e,0x0000002b,0x0000002c,0x00050041,0x00000011,0x00000030, - 0x0000001e,0x0000000d,0x0003003e,0x00000030,0x0000002f,0x000100fd,0x00010038 + 0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000, + 0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00040005,0x0000001c, + 0x736f5061,0x00000000,0x00060005,0x0000001e,0x73755075,0x6e6f4368,0x6e617473,0x00000074, + 0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001, + 0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b, + 0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015, + 0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047, + 0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e, + 0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008, + 0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017, + 0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020, + 0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015, + 0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020, + 0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020, + 0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020, + 0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020, + 0x00000017,0x00000003,0x00000008,0x0003001e,0x00000019,0x00000007,0x00040020,0x0000001a, + 0x00000003,0x00000019,0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004003b,0x00000014, + 0x0000001c,0x00000001,0x0004001e,0x0000001e,0x00000008,0x00000008,0x00040020,0x0000001f, + 0x00000009,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000009,0x00040020,0x00000021, + 0x00000009,0x00000008,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006, + 0x00000029,0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, + 0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012, + 0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016, + 0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018, + 0x00000016,0x0004003d,0x00000008,0x0000001d,0x0000001c,0x00050041,0x00000021,0x00000022, + 0x00000020,0x0000000d,0x0004003d,0x00000008,0x00000023,0x00000022,0x00050085,0x00000008, + 0x00000024,0x0000001d,0x00000023,0x00050041,0x00000021,0x00000025,0x00000020,0x00000013, + 0x0004003d,0x00000008,0x00000026,0x00000025,0x00050081,0x00000008,0x00000027,0x00000024, + 0x00000026,0x00050051,0x00000006,0x0000002a,0x00000027,0x00000000,0x00050051,0x00000006, + 0x0000002b,0x00000027,0x00000001,0x00070050,0x00000007,0x0000002c,0x0000002a,0x0000002b, + 0x00000028,0x00000029,0x00050041,0x00000011,0x0000002d,0x0000001b,0x0000000d,0x0003003e, + 0x0000002d,0x0000002c,0x000100fd,0x00010038 }; -static uint32_t __glsl_shader_frag_spv[] = +static uint32_t __glsl_shader_frag_spv[] = { 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b, 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, @@ -406,7 +400,6 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) // Create the Image View: { - VkResult err; VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; info.image = g_FontImage; diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 1893e033..7107c1f5 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -49,7 +49,7 @@ static void check_vk_result(VkResult err) { if (err == 0) return; printf("VkResult %d\n", err); - if (err < 0) + if (err < 0) abort(); } @@ -204,14 +204,48 @@ static void setup_vulkan(GLFWwindow* window) err = glfwCreateWindowSurface(g_Instance, window, g_Allocator, &g_Surface); check_vk_result(err); } - - // Get GPU + + // Get GPU (WARNING here we assume the first gpu is one we can use) { uint32_t count = 1; err = vkEnumeratePhysicalDevices(g_Instance, &count, &g_Gpu); check_vk_result(err); } + // Get queue + { + uint32_t count; + vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, nullptr); + VkQueueFamilyProperties *queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties)*count); + vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, queues); + for(uint32_t i=0; i Date: Sun, 13 Nov 2016 04:28:26 +0100 Subject: [PATCH 368/400] Vulkan example: Fix gamma for some implementations. --- examples/vulkan_example/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index 7107c1f5..f1efd8b8 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -24,6 +24,7 @@ static uint32_t g_QueueFamily = 0; static VkQueue g_Queue = VK_NULL_HANDLE; static VkFormat g_Format = VK_FORMAT_B8G8R8A8_UNORM; +static VkFormat g_ViewFormat = VK_FORMAT_B8G8R8A8_UNORM; static VkColorSpaceKHR g_ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; static VkImageSubresourceRange g_ImageRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; @@ -119,7 +120,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) // Create the Render Pass: { VkAttachmentDescription attachment = {}; - attachment.format = g_Format; + attachment.format = g_ViewFormat; attachment.samples = VK_SAMPLE_COUNT_1_BIT; attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -149,7 +150,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; info.viewType = VK_IMAGE_VIEW_TYPE_2D; - info.format = g_Format; + info.format = g_ViewFormat; info.components.r = VK_COMPONENT_SWIZZLE_R; info.components.g = VK_COMPONENT_SWIZZLE_G; info.components.b = VK_COMPONENT_SWIZZLE_B; From a5600b6e5904c19cbfe752806778bb9122388cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Sun, 13 Nov 2016 05:23:33 +0100 Subject: [PATCH 369/400] Vulkan example: Proper surface format search. --- examples/vulkan_example/main.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index f1efd8b8..b0535e84 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -23,7 +23,7 @@ static VkRenderPass g_RenderPass = VK_NULL_HANDLE; static uint32_t g_QueueFamily = 0; static VkQueue g_Queue = VK_NULL_HANDLE; -static VkFormat g_Format = VK_FORMAT_B8G8R8A8_UNORM; +static VkFormat g_ImageFormat = VK_FORMAT_B8G8R8A8_UNORM; static VkFormat g_ViewFormat = VK_FORMAT_B8G8R8A8_UNORM; static VkColorSpaceKHR g_ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; static VkImageSubresourceRange g_ImageRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; @@ -76,7 +76,7 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = g_Surface; - info.imageFormat = g_Format; + info.imageFormat = g_ImageFormat; info.imageColorSpace = g_ColorSpace; info.imageArrayLayers = 1; info.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; @@ -216,7 +216,7 @@ static void setup_vulkan(GLFWwindow* window) // Get queue { uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, nullptr); + vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, NULL); VkQueueFamilyProperties *queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties)*count); vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, queues); for(uint32_t i=0; i Date: Sun, 13 Nov 2016 17:57:43 +0100 Subject: [PATCH 370/400] Examples: Vulkan: Coding style fixes (#910) --- examples/vulkan_example/main.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index b0535e84..8116e08c 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -217,10 +217,12 @@ static void setup_vulkan(GLFWwindow* window) { uint32_t count; vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, NULL); - VkQueueFamilyProperties *queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties)*count); + VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, queues); - for(uint32_t i=0; i Date: Sun, 13 Nov 2016 21:42:40 +0100 Subject: [PATCH 371/400] Tools: binary_to_compressed_c.cpp : comments + link to precompiled binaries --- README.md | 6 +++--- extra_fonts/binary_to_compressed_c.cpp | 16 +++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ae915fc8..1e0d1bc4 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ _A common misunderstanding is that some people think immediate mode gui == immed ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. -Demo ----- +Binaries/Demo +------------- You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download Windows binaries of the demo app here. -- [imgui-demo-binaries-20160410.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20160410.zip) (Windows binaries, ImGui 1.48+ 2016/04/10, 4 executables, 534 KB) +- [imgui-demo-binaries-20161113.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20161113.zip) (Windows binaries, ImGui 1.49+ 2016/11/13, 5 executables, 588 KB) Gallery diff --git a/extra_fonts/binary_to_compressed_c.cpp b/extra_fonts/binary_to_compressed_c.cpp index 4d0471a8..79beaad6 100644 --- a/extra_fonts/binary_to_compressed_c.cpp +++ b/extra_fonts/binary_to_compressed_c.cpp @@ -1,12 +1,18 @@ // ImGui - binary_to_compressed_c.cpp -// Helper tool to turn a file into a C array. -// The data is first compressed with stb_compress() to reduce source code size. -// Then encoded in Base85 to fit in a string so we can fit roughly 4 bytes of compressed data into 5 bytes of source code (suggested by @mmalex) -// (If we used 32-bits constants it would require take 11 bytes of source code to encode 4 bytes.) -// Useful if you want to embed fonts into your code. +// Helper tool to turn a file into a C array, if you want to embed font data in your source code. + +// The data is first compressed with stb_compress() to reduce source code size, +// then encoded in Base85 to fit in a string so we can fit roughly 4 bytes of compressed data into 5 bytes of source code (suggested by @mmalex) +// (If we used 32-bits constants it would require take 11 bytes of source code to encode 4 bytes, and be endianness dependent) // Note that even with compression, the output array is likely to be bigger than the binary file.. // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() +// Single file application, build with: +// # cl.exe binary_to_compressed_c.cpp +// # gcc binary_to_compressed_c.cpp +// etc. +// You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui + #define _CRT_SECURE_NO_WARNINGS #include #include From 104b3810237d4a959ff421fea14c6fc0fd8d0b79 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Nov 2016 16:43:36 +0100 Subject: [PATCH 372/400] Using _wfopen() under Windows+MSVC because fopen() doesn't support UTF-8 encoding. Wrapped as ImFileOpen(). (#917) --- imgui.cpp | 22 +++++++++++++++++++--- imgui_internal.h | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 75c83fdb..5af77333 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1293,6 +1293,22 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& } } +FILE* ImFileOpen(const char* filename, const char* mode) +{ +#ifdef _MSC_VER + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can) + const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; + const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; + ImVector buf; + buf.resize(filename_wsize + mode_wsize); + ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL); + ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL); + return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]); +#else + return fopen(filename, mode); +#endif +} + // Load file content into memory // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree() void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes) @@ -1302,7 +1318,7 @@ void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* *out_file_size = 0; FILE* f; - if ((f = fopen(filename, file_open_mode)) == NULL) + if ((f = ImFileOpen(filename, file_open_mode)) == NULL) return NULL; long file_size_signed; @@ -2501,7 +2517,7 @@ static void SaveSettings() // Write .ini file // If a window wasn't opened in this session we preserve its settings - FILE* f = fopen(filename, "wt"); + FILE* f = ImFileOpen(filename, "wt"); if (!f) return; for (int i = 0; i != g.Settings.Size; i++) @@ -5784,7 +5800,7 @@ void ImGui::LogToFile(int max_depth, const char* filename) return; } - g.LogFile = fopen(filename, "ab"); + g.LogFile = ImFileOpen(filename, "ab"); if (!g.LogFile) { IM_ASSERT(g.LogFile != NULL); // Consider this an error diff --git a/imgui_internal.h b/imgui_internal.h index 5d358253..ff188b0f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -89,6 +89,7 @@ IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, cons // Helpers: Misc IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings IMGUI_API void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); +IMGUI_API FILE* ImOpenFile(const char* filename, const char* file_open_mode); IMGUI_API bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c); static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; } static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } From 61d5b46307a299f75d898c9e4967bd291ddad67e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Nov 2016 17:38:33 +0100 Subject: [PATCH 373/400] SliderInt, SliderFloat(): support reverse direction (#854) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5af77333..2400ddca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6539,10 +6539,10 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v } // Calculate slider grab positioning + float v_clamped = (v_min < v_max) ? ImClamp(*v, v_min, v_max) : ImClamp(*v, v_max, v_min); float grab_t; if (is_non_linear) { - float v_clamped = ImClamp(*v, v_min, v_max); if (v_clamped < 0.0f) { const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min); @@ -6557,7 +6557,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v else { // Linear slider - grab_t = (ImClamp(*v, v_min, v_max) - v_min) / (v_max - v_min); + grab_t = (v_clamped - v_min) / (v_max - v_min); } // Draw From a868c32ed15a070568400efda1a5e7387526fe09 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Nov 2016 17:43:32 +0100 Subject: [PATCH 374/400] SliderInt, SliderFloat: Renaming --- imgui.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2400ddca..2719f829 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6491,18 +6491,18 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v if (g.IO.MouseDown[0]) { const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; - float normalized_pos = ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f); + float clicked_t = ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f); if (!is_horizontal) - normalized_pos = 1.0f - normalized_pos; + clicked_t = 1.0f - clicked_t; float new_value; if (is_non_linear) { // Account for logarithmic scale on both sides of the zero - if (normalized_pos < linear_zero_pos) + if (clicked_t < linear_zero_pos) { // Negative: rescale to the negative range before powering - float a = 1.0f - (normalized_pos / linear_zero_pos); + float a = 1.0f - (clicked_t / linear_zero_pos); a = powf(a, power); new_value = ImLerp(ImMin(v_max,0.0f), v_min, a); } @@ -6511,9 +6511,9 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v // Positive: rescale to the positive range before powering float a; if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f) - a = (normalized_pos - linear_zero_pos) / (1.0f - linear_zero_pos); + a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos); else - a = normalized_pos; + a = clicked_t; a = powf(a, power); new_value = ImLerp(ImMax(v_min,0.0f), v_max, a); } @@ -6521,7 +6521,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v else { // Linear slider - new_value = ImLerp(v_min, v_max, normalized_pos); + new_value = ImLerp(v_min, v_max, clicked_t); } // Round past decimal precision From 219e4fb8fbec8ba0e811b1b8d8395f920d44b0bb Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Nov 2016 17:49:04 +0100 Subject: [PATCH 375/400] SliderInt, SliderFloat: Passing v_min==v_max disable setting value from clicking/dragging (#919) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 2719f829..e4d6789b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6526,7 +6526,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v // Round past decimal precision new_value = RoundScalar(new_value, decimal_precision); - if (*v != new_value) + if (*v != new_value && (v_min != v_max)) { *v = new_value; value_changed = true; From 004e8637271a72e0284b42b5a904a658f0adb216 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Nov 2016 18:32:24 +0100 Subject: [PATCH 376/400] Split SliderBehaviorCalcRatioFromValue() out from SliderBehavior() --- imgui.cpp | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e4d6789b..fc640be9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6446,6 +6446,28 @@ float ImGui::RoundScalar(float value, int decimal_precision) return negative ? -value : value; } +static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) +{ + const bool is_non_linear = (power < 1.0f-0.00001f) && (power > 1.0f-0.00001f); + const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); + if (is_non_linear) + { + if (v_clamped < 0.0f) + { + const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min); + return (1.0f - powf(f, 1.0f/power)) * linear_zero_pos; + } + else + { + const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min)); + return linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos); + } + } + + // Linear slider + return (v_clamped - v_min) / (v_max - v_min); +} + bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags) { ImGuiContext& g = *GImGui; @@ -6539,26 +6561,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v } // Calculate slider grab positioning - float v_clamped = (v_min < v_max) ? ImClamp(*v, v_min, v_max) : ImClamp(*v, v_max, v_min); - float grab_t; - if (is_non_linear) - { - if (v_clamped < 0.0f) - { - const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min); - grab_t = (1.0f - powf(f, 1.0f/power)) * linear_zero_pos; - } - else - { - const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min)); - grab_t = linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos); - } - } - else - { - // Linear slider - grab_t = (v_clamped - v_min) / (v_max - v_min); - } + float grab_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); // Draw if (!is_horizontal) From 0a483379af3c0cd7f0c6856aba0faacfd70670e3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Nov 2016 18:34:46 +0100 Subject: [PATCH 377/400] Split SliderBehaviorCalcRatioFromValue() out of SliderBehavior(), fix + Not using fabsf() anymore --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fc640be9..1f34d15d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6448,7 +6448,7 @@ float ImGui::RoundScalar(float value, int decimal_precision) static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) { - const bool is_non_linear = (power < 1.0f-0.00001f) && (power > 1.0f-0.00001f); + const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); if (is_non_linear) { @@ -6477,7 +6477,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v // Draw frame RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - const bool is_non_linear = fabsf(power - 1.0f) > 0.0001f; + const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0; const float grab_padding = 2.0f; From 94c77edfa52c64431d6731377b7f2e65b27b4f50 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Nov 2016 11:03:48 +0100 Subject: [PATCH 378/400] SliderInt, SliderFloat() Better display support for v_min==v_max range. (#919) --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 1f34d15d..42396eeb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6448,6 +6448,9 @@ float ImGui::RoundScalar(float value, int decimal_precision) static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) { + if (v_min == v_max) + return 0.0f; + const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); if (is_non_linear) From 449c47c789302f5bb9287bfacfa7640c35abbc67 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Nov 2016 11:05:24 +0100 Subject: [PATCH 379/400] SliderInt, SliderFloat() interacting enforce modifying to the value to be consistent with other widget behaviors (#919) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 42396eeb..23ed4ca4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6551,7 +6551,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v // Round past decimal precision new_value = RoundScalar(new_value, decimal_precision); - if (*v != new_value && (v_min != v_max)) + if (*v != new_value) { *v = new_value; value_changed = true; From bbd0a37bd282c8cb79d20522db446e4989f83661 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Nov 2016 20:30:36 +0100 Subject: [PATCH 380/400] ImFileOpen: MinGW uses _wfopen() codepath to support UTF-8 filenames (#917) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 23ed4ca4..81055351 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1295,7 +1295,7 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& FILE* ImFileOpen(const char* filename, const char* mode) { -#ifdef _MSC_VER +#if defined(_WIN32) && !defined(__CYGWIN__) // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can) const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; From ca9a91853584c0095be233a19a7b3705914457bc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Nov 2016 20:43:11 +0100 Subject: [PATCH 381/400] SliderInt(): Fixed reverse direction mode when (v_max-v_min)==-1 (#854) (+ ref #919) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 81055351..aba57ed0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6489,7 +6489,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v if (decimal_precision > 0) grab_sz = ImMin(style.GrabMinSize, slider_sz); else - grab_sz = ImMin(ImMax(1.0f * (slider_sz / (v_max-v_min+1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit + grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit const float slider_usable_sz = slider_sz - grab_sz; const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz*0.5f; const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz*0.5f; From 9235e0da468b35249474e981eb44ee43a56a2376 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2016 21:07:26 +0100 Subject: [PATCH 382/400] SliderInt, SliderFloat(): Fixed edge case where style.GrabMinSize being bigger than slider width can lead to a division by zero (#919) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index aba57ed0..6c259478 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6516,7 +6516,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v if (g.IO.MouseDown[0]) { const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y; - float clicked_t = ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f); + float clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; if (!is_horizontal) clicked_t = 1.0f - clicked_t; From 0b6211f90786edb3dfb770aa35a1e025a9019be8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2016 21:46:21 +0100 Subject: [PATCH 383/400] Fixed clicking on a window's void while staying still overzealously marking .ini settings as dirty (#923) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6c259478..7598c24e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2220,7 +2220,7 @@ void ImGui::NewFrame() if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoMove)) { g.MovedWindow->PosFloat += g.IO.MouseDelta; - if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoSavedSettings) && (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)) MarkSettingsDirty(); } FocusWindow(g.MovedWindow); From 55d651812d435d660e14aaede0916b65d4c3994c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Nov 2016 21:55:20 +0100 Subject: [PATCH 384/400] Renaming and massaging internal Settings/Ini functions (#923) --- imgui.cpp | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7598c24e..5a45931f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -684,9 +684,9 @@ static void AddWindowToSortedBuffer(ImVector& out_sort static ImGuiIniData* FindWindowSettings(const char* name); static ImGuiIniData* AddWindowSettings(const char* name); -static void LoadSettings(); -static void SaveSettings(); -static void MarkSettingsDirty(); +static void LoadIniSettingsFromDisk(const char* ini_filename); +static void SaveIniSettingsToDisk(const char* ini_filename); +static void MarkIniSettingsDirty(); static void PushColumnClipRect(int column_index = -1); static ImRect GetVisibleRect(); @@ -2135,7 +2135,7 @@ void ImGui::NewFrame() IM_PLACEMENT_NEW(g.LogClipboard) ImGuiTextBuffer(); IM_ASSERT(g.Settings.empty()); - LoadSettings(); + LoadIniSettingsFromDisk(g.IO.IniFilename); g.Initialized = true; } @@ -2221,7 +2221,7 @@ void ImGui::NewFrame() { g.MovedWindow->PosFloat += g.IO.MouseDelta; if (!(g.MovedWindow->Flags & ImGuiWindowFlags_NoSavedSettings) && (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)) - MarkSettingsDirty(); + MarkIniSettingsDirty(); } FocusWindow(g.MovedWindow); } @@ -2243,7 +2243,7 @@ void ImGui::NewFrame() { g.SettingsDirtyTimer -= g.IO.DeltaTime; if (g.SettingsDirtyTimer <= 0.0f) - SaveSettings(); + SaveIniSettingsToDisk(g.IO.IniFilename); } // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow @@ -2370,7 +2370,7 @@ void ImGui::Shutdown() if (!g.Initialized) return; - SaveSettings(); + SaveIniSettingsToDisk(g.IO.IniFilename); for (int i = 0; i < g.Windows.Size; i++) { @@ -2450,15 +2450,14 @@ static ImGuiIniData* AddWindowSettings(const char* name) // Zero-tolerance, poor-man .ini parsing // FIXME: Write something less rubbish -static void LoadSettings() +static void LoadIniSettingsFromDisk(const char* ini_filename) { ImGuiContext& g = *GImGui; - const char* filename = g.IO.IniFilename; - if (!filename) + if (!ini_filename) return; int file_size; - char* file_data = (char*)ImLoadFileToMemory(filename, "rb", &file_size, 1); + char* file_data = (char*)ImLoadFileToMemory(ini_filename, "rb", &file_size, 1); if (!file_data) return; @@ -2496,11 +2495,11 @@ static void LoadSettings() ImGui::MemFree(file_data); } -static void SaveSettings() +static void SaveIniSettingsToDisk(const char* ini_filename) { ImGuiContext& g = *GImGui; - const char* filename = g.IO.IniFilename; - if (!filename) + g.SettingsDirtyTimer = 0.0f; + if (!ini_filename) return; // Gather data from windows that were active during this session @@ -2517,7 +2516,7 @@ static void SaveSettings() // Write .ini file // If a window wasn't opened in this session we preserve its settings - FILE* f = ImFileOpen(filename, "wt"); + FILE* f = ImFileOpen(ini_filename, "wt"); if (!f) return; for (int i = 0; i != g.Settings.Size; i++) @@ -2538,7 +2537,7 @@ static void SaveSettings() fclose(f); } -static void MarkSettingsDirty() +static void MarkIniSettingsDirty() { ImGuiContext& g = *GImGui; if (g.SettingsDirtyTimer <= 0.0f) @@ -4010,7 +4009,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us { window->Collapsed = !window->Collapsed; if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); + MarkIniSettingsDirty(); FocusWindow(window); } } @@ -4085,7 +4084,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (window->AutoFitFramesY > 0) window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); + MarkIniSettingsDirty(); } } @@ -4214,7 +4213,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // Manual auto-fit when double-clicking ApplySizeFullWithConstraint(window, size_auto_fit); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); + MarkIniSettingsDirty(); SetActiveID(0); } else if (held) @@ -4222,7 +4221,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position ApplySizeFullWithConstraint(window, (g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize()) - window->Pos); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - MarkSettingsDirty(); + MarkIniSettingsDirty(); } window->Size = window->SizeFull; From 36d78e05651877c69eab0e4aea48cd20d4ce8f9c Mon Sep 17 00:00:00 2001 From: Nicolas Guillemot Date: Sun, 4 Dec 2016 12:54:31 -0800 Subject: [PATCH 385/400] const correctness for Combo and ListBox Since Combo and ListBox only read and display the list of items, they should not modify the pointers inside the array of pointers passed in. Adding "const" here makes it possible to call these functions with such an array of const pointers. Previously, a cast to "const char**" was required as a workaround, otherwise there was a compile error. --- imgui.cpp | 6 +++--- imgui.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5a45931f..09b2ae77 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8399,7 +8399,7 @@ bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_fla static bool Items_ArrayGetter(void* data, int idx, const char** out_text) { - const char** items = (const char**)data; + const char* const* items = (const char* const*)data; if (out_text) *out_text = items[idx]; return true; @@ -8426,7 +8426,7 @@ static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) } // Combo box helper allowing to pass an array of strings. -bool ImGui::Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items) +bool ImGui::Combo(const char* label, int* current_item, const char* const* items, int items_count, int height_in_items) { const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); return value_changed; @@ -8703,7 +8703,7 @@ void ImGui::ListBoxFooter() EndGroup(); } -bool ImGui::ListBox(const char* label, int* current_item, const char** items, int items_count, int height_items) +bool ImGui::ListBox(const char* label, int* current_item, const char* const* items, int items_count, int height_items) { const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); return value_changed; diff --git a/imgui.h b/imgui.h index 776b4d5c..40e21580 100644 --- a/imgui.h +++ b/imgui.h @@ -265,7 +265,7 @@ namespace ImGui IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool RadioButton(const char* label, bool active); IMGUI_API bool RadioButton(const char* label, int* v, int v_button); - IMGUI_API bool Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); + IMGUI_API bool Combo(const char* label, int* current_item, const char* const* items, int items_count, int height_in_items = -1); IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items = -1); // separate items with \0, end item-list with \0\0 IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); IMGUI_API bool ColorButton(const ImVec4& col, bool small_height = false, bool outline_border = true); @@ -339,7 +339,7 @@ namespace ImGui // Widgets: Selectable / Lists IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); - IMGUI_API bool ListBox(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); + IMGUI_API bool ListBox(const char* label, int* current_item, const char* const* items, int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. make sure to call ListBoxFooter() afterwards. IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " From 52308a54f86c367ba79af84225fb17bc30bbfc9e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Dec 2016 11:05:41 +0100 Subject: [PATCH 386/400] Demo: comments --- imgui_demo.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e30a004e..d42d1486 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1123,7 +1123,8 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetItemsLineHeightWithSpacing()*7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); for (int line = 0; line < lines; line++) { - // Display random stuff + // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off + // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API) int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); for (int n = 0; n < num_buttons; n++) { @@ -1181,6 +1182,8 @@ void ImGui::ShowTestWindow(bool* p_open) const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; static bool toggles[] = { true, false, false, false, false }; + // Simple selection popup + // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label) if (ImGui::Button("Select..")) ImGui::OpenPopup("select"); ImGui::SameLine(); @@ -1195,6 +1198,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImGui::EndPopup(); } + // Showing a menu with toggles if (ImGui::Button("Toggle..")) ImGui::OpenPopup("toggle"); if (ImGui::BeginPopup("toggle")) @@ -1229,8 +1233,8 @@ void ImGui::ShowTestWindow(bool* p_open) } if (ImGui::Button("Popup Menu..")) - ImGui::OpenPopup("popup from button"); - if (ImGui::BeginPopup("popup from button")) + ImGui::OpenPopup("FilePopup"); + if (ImGui::BeginPopup("FilePopup")) { ShowExampleMenuFile(); ImGui::EndPopup(); From d74a3349e90308be9a24daf774bfd50662e04d62 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Dec 2016 23:15:38 +0100 Subject: [PATCH 387/400] Examples: DirectX9: Explicitely setting viewport to match that other examples are doing (#937) --- examples/directx9_example/imgui_impl_dx9.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 82e638ef..93472f65 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -94,6 +94,15 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) g_pd3dDevice->SetIndices(g_pIB); g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); + // Setup viewport + D3DVIEWPORT9 vp; + vp.X = vp.Y = 0; + vp.Width = (DWORD)io.DisplaySize.x; + vp.Height = (DWORD)io.DisplaySize.y; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + g_pd3dDevice->SetViewport(&vp); + // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing g_pd3dDevice->SetPixelShader(NULL); g_pd3dDevice->SetVertexShader(NULL); From baa2e3b45184290c6bab2e37b0483390e5642454 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Dec 2016 18:42:52 +0100 Subject: [PATCH 388/400] Minor documentation tweaks --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5a45931f..75dd64e0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5,6 +5,7 @@ // Newcomers, read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui // Releases change-log at https://github.com/ocornut/imgui/releases +// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/772 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // This library is free but I need your support to sustain development and maintenance. // If you work for a company, please consider financial support, e.g: https://www.patreon.com/imgui @@ -280,7 +281,6 @@ Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name in the code, there will likely be a comment about it. Please report any issue to the GitHub page! - Q: What is ImTextureID and how do I display an image? A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function. ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry! @@ -464,7 +464,7 @@ ISSUES & TODO-LIST ================== Issue numbers (#) refer to github issues listed at https://github.com/ocornut/imgui/issues - The list below consist mostly of notes of things to do before they are requested/discussed by users (at that point it usually happens on the github) + The list below consist mostly of ideas noted down before they are requested/discussed by users (at which point it usually moves to the github) - doc: add a proper documentation+regression testing system (#435) - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. From 1396659b7282c11edbe126bf36202c18661fd399 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Dec 2016 20:12:43 +0100 Subject: [PATCH 389/400] Examples: Speculative fix for OSX Makefile to make Travis happy (re #812) --- examples/opengl2_example/Makefile | 4 ++-- examples/opengl3_example/Makefile | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/opengl2_example/Makefile b/examples/opengl2_example/Makefile index bd79d1ba..631abe4b 100644 --- a/examples/opengl2_example/Makefile +++ b/examples/opengl2_example/Makefile @@ -29,11 +29,11 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" LIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo - LIBS += -L/usr/local/lib -lglfw3 + #LIBS += -L/usr/local/lib -lglfw3 + LIBS += -L/usr/local/lib -lglfw CXXFLAGS = -I../../ -I/usr/local/include CXXFLAGS += -Wall -Wformat -# CXXFLAGS += -D__APPLE__ CFLAGS = $(CXXFLAGS) endif diff --git a/examples/opengl3_example/Makefile b/examples/opengl3_example/Makefile index c824f99a..5d91708a 100644 --- a/examples/opengl3_example/Makefile +++ b/examples/opengl3_example/Makefile @@ -31,12 +31,11 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" LIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo - LIBS += -L/usr/local/lib -lglfw3 - #LIBS += -L/usr/local/lib -lglfw + #LIBS += -L/usr/local/lib -lglfw3 + LIBS += -L/usr/local/lib -lglfw CXXFLAGS = -I../../ -I../libs/gl3w -I/usr/local/include CXXFLAGS += -Wall -Wformat -# CXXFLAGS += -D__APPLE__ CFLAGS = $(CXXFLAGS) endif From f4f0ee750f554de8c9aa52a1bd12c819de380032 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 21 Dec 2016 21:13:43 +0100 Subject: [PATCH 390/400] Update README.md --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index 1e0d1bc4..9c352696 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,40 @@ Binaries/Demo You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download Windows binaries of the demo app here. - [imgui-demo-binaries-20161113.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20161113.zip) (Windows binaries, ImGui 1.49+ 2016/11/13, 5 executables, 588 KB) +Bindings +-------- + +_NB: those third-party bindings may be more or less maintained, more or less close to the spirit of original API. People who create language bindings sometimes haven't used the C++ API themselves. ImGui was designed with C++ in mind and some of the subtleties may be lost in translation with other languages. If your language supports it, I would suggest replicating the function overloading and default parameters used in the original, else the API may be harder to use. In doubt, always check the original C++ version first!_ + +Languages: +- cimgui: thin c-api wrapper for ImGui https://github.com/Extrawurst/cimgui +- ImGui.NET: An ImGui wrapper for .NET Core https://github.com/mellinoe/ImGui.NET +- imgui-rs: Rust bindings for dear imgui https://github.com/Gekkio/imgui-rs +- DerelictImgui: Dynamic bindings for the D programming language: https://github.com/Extrawurst/DerelictImgui +- CyImGui: Python bindings for dear imgui using Cython: https://github.com/chromy/cyimgui +- pyimgui: Another Python bindings for dear imgui: https://github.com/swistakm/pyimgui +- LUA: https://github.com/patrickriordan/imgui_lua_bindings + +Frameworks: +- Main ImGui repository include examples for DirectX9, DirectX10, DirectX11, OpenGL2/3, Vulkan, Allegro 5, SDL+GL2/3, iOS and Marmalade: https://github.com/ocornut/imgui/tree/master/examples +- Unmerged PR: DirectX12 example (with issues) https://github.com/ocornut/imgui/pull/301 +- Unmerged PR: SDL2 + OpenGLES + Emscripten example https://github.com/ocornut/imgui/pull/336 +- Unmerged PR: FreeGlut + OpenGL2 example https://github.com/ocornut/imgui/pull/801 +- Unmerged PR: Native Win32 and OSX example https://github.com/ocornut/imgui/pull/281 +- Unmerged PR: Android Example https://github.com/ocornut/imgui/pull/421 +- Cinder backend for dear imgui https://github.com/simongeilfus/Cinder-ImGui +- FlexGUI: Flexium/SFML backend for dear imgui https://github.com/DXsmiley/FlexGUI +- IrrIMGUI: Irrlicht backend for dear imgui https://github.com/ZahlGraf/IrrIMGUI +- LÖVE backend for dear imgui https://github.com/slages/love-imgui +- Ogre backend for dear imgui https://bitbucket.org/LMCrashy/ogreimgui/src +- ofxImGui: openFrameworks backend for dear imgui https://github.com/jvcleave/ofxImGui +- SFML backend for dear imgui https://github.com/EliasD/imgui-sfml +- SFML backend for dear imgui https://github.com/Mischa-Alff/imgui-backends +- cocos2d-x with imgui https://github.com/c0i/imguix https://github.com/ocornut/imgui/issues/551 +- NanoRT: software raytraced version https://github.com/syoyo/imgui/tree/nanort/examples/raytrace_example + +For other bindings: see [this page](https://github.com/ocornut/imgui/wiki/Links/). +Please contact me with the Issues tracker or Twitter to fix/update this list. Gallery ------- From db593220fc419547b80e188b104051d39fc1a8e3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Dec 2016 11:34:23 +0100 Subject: [PATCH 391/400] Comments, clarified use of io.MouseDelta (#942) (ImGuiIO structure layout changed) --- imgui.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.h b/imgui.h index 40e21580..38ce2d2d 100644 --- a/imgui.h +++ b/imgui.h @@ -788,29 +788,29 @@ struct ImGuiIO ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper. // Functions - IMGUI_API void AddInputCharacter(ImWchar c); // Helper to add a new character into InputCharacters[] - IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Helper to add new characters into InputCharacters[] from an UTF-8 string - inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Helper to clear the text input buffer + IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[] + IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Add new characters into InputCharacters[] from an UTF-8 string + inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Clear the text input buffer manually //------------------------------------------------------------------ - // Output - Retrieve after calling NewFrame(), you can use them to discard inputs or hide them from the rest of your application + // Output - Retrieve after calling NewFrame() //------------------------------------------------------------------ - bool WantCaptureMouse; // Mouse is hovering a window or widget is active (= ImGui will use your mouse input) - bool WantCaptureKeyboard; // Widget is active (= ImGui will use your keyboard input) - bool WantTextInput; // Some text input widget is active, which will read input characters from the InputCharacters array. - float Framerate; // Framerate estimation, in frame per second. Rolling average estimation based on IO.DeltaTime over 120 frames + bool WantCaptureMouse; // Mouse is hovering a window or widget is active (= ImGui will use your mouse input). Use to hide mouse from the rest of your application + bool WantCaptureKeyboard; // Widget is active (= ImGui will use your keyboard input). Use to hide keyboard from the rest of your application + bool WantTextInput; // Some text input widget is active, which will read input characters from the InputCharacters array. Use to activate on screen keyboard if your system needs one + float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames int MetricsAllocs; // Number of active memory allocations int MetricsRenderVertices; // Vertices output during last call to Render() int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 - int MetricsActiveWindows; // Number of visible windows (exclude child windows) + int MetricsActiveWindows; // Number of visible root windows (exclude child windows) + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are negative, so a disappearing/reappearing mouse won't have a huge delta for one frame. //------------------------------------------------------------------ // [Private] ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ - ImVec2 MousePosPrev; // Previous mouse position - ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are negative to allow mouse enabling/disabling. + ImVec2 MousePosPrev; // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame()) bool MouseClicked[5]; // Mouse button went from !Down to Down ImVec2 MouseClickedPos[5]; // Position at time of clicking float MouseClickedTime[5]; // Time of last click (used to figure out double-click) From 68df09cf4755f2d5ee4c015f1f8fc8f2bb122645 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 1 Jan 2017 20:11:40 +0100 Subject: [PATCH 392/400] Fixed word-wrapping which would never wrap after a 1 character word. (thanks @sronsse) --- imgui_demo.cpp | 4 ++-- imgui_draw.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d42d1486..e9b5da51 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -362,7 +362,7 @@ void ImGui::ShowTestWindow(bool* p_open) ImVec2 pos = ImGui::GetCursorScreenPos(); ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); - ImGui::Text("lazy dog. This paragraph is made to fit within %.0f pixels. The quick brown fox jumps over the lazy dog.", wrap_width); + ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); ImGui::PopTextWrapPos(); @@ -370,7 +370,7 @@ void ImGui::ShowTestWindow(bool* p_open) pos = ImGui::GetCursorScreenPos(); ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255)); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); - ImGui::Text("aaaaaaaa bbbbbbbb, cccccccc,dddddddd. eeeeeeee ffffffff. gggggggg!hhhhhhhh"); + ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255)); ImGui::PopTextWrapPos(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a660e30c..a1d58c0e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1851,6 +1851,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c { line_width += blank_width; blank_width = 0.0f; + word_end = s; } blank_width += char_width; inside_word = false; From 714beb217cc12b27fe42ae6c5539f1488aa66d45 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 7 Jan 2017 20:18:45 +0100 Subject: [PATCH 393/400] Demo: Console: Fixed a completion bug when multiple candidates are equals and match until the end. --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e9b5da51..dda0a53d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2316,7 +2316,7 @@ struct ExampleAppConsole for (int i = 0; i < candidates.Size && all_candidates_matches; i++) if (i == 0) c = toupper(candidates[i][match_len]); - else if (c != toupper(candidates[i][match_len])) + else if (c == 0 || c != toupper(candidates[i][match_len])) all_candidates_matches = false; if (!all_candidates_matches) break; From cffdbfe01b476b1be4f3ba825b5ff823e06f6e8e Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 10 Jan 2017 10:36:07 +0100 Subject: [PATCH 394/400] Comments (#972) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 38ce2d2d..9d84a94f 100644 --- a/imgui.h +++ b/imgui.h @@ -372,7 +372,7 @@ namespace ImGui // Popups IMGUI_API void OpenPopup(const char* str_id); // mark popup as open. popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). IMGUI_API bool BeginPopup(const char* str_id); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true! - IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (can't close them by clicking outside) + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (block interactions behind the modal window, can't close the modal window by clicking outside) IMGUI_API bool BeginPopupContextItem(const char* str_id, int mouse_button = 1); // helper to open and begin popup when clicked on last item. read comments in .cpp! IMGUI_API bool BeginPopupContextWindow(bool also_over_items = true, const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on current window. IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (no window). From 6257b5814a936617741a14fa11c98af15d53ca49 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 11 Jan 2017 20:56:55 +0100 Subject: [PATCH 395/400] Added an explicit (internal) ClearActiveID() helper and removed the default NULL window parameter to internal SetActiveID(), --- imgui.cpp | 37 +++++++++++++++++++++---------------- imgui_internal.h | 1 + 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c60c1d9c..c7b16b26 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1858,7 +1858,7 @@ ImGuiWindow* ImGui::GetParentWindow() return g.CurrentWindowStack[(unsigned int)g.CurrentWindowStack.Size - 2]; } -void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) { ImGuiContext& g = *GImGui; g.ActiveId = id; @@ -1869,6 +1869,11 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) g.ActiveIdWindow = window; } +void ImGui::ClearActiveID() +{ + SetActiveID(0, NULL); +} + void ImGui::SetHoveredID(ImGuiID id) { ImGuiContext& g = *GImGui; @@ -2204,7 +2209,7 @@ void ImGui::NewFrame() g.HoveredId = 0; g.HoveredIdAllowOverlap = false; if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) - SetActiveID(0); + ClearActiveID(); g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdIsAlive = false; g.ActiveIdIsJustActivated = false; @@ -2227,7 +2232,7 @@ void ImGui::NewFrame() } else { - SetActiveID(0); + ClearActiveID(); g.MovedWindow = NULL; g.MovedWindowMoveId = 0; } @@ -4214,7 +4219,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us ApplySizeFullWithConstraint(window, size_auto_fit); if (!(flags & ImGuiWindowFlags_NoSavedSettings)) MarkIniSettingsDirty(); - SetActiveID(0); + ClearActiveID(); } else if (held) { @@ -4563,7 +4568,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) // Steal focus on active widgets if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it.. if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window) - SetActiveID(0); + ClearActiveID(); // Bring to front if ((window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) || g.Windows.back() == window) @@ -5536,7 +5541,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { if (out_hovered) *out_hovered = false; if (out_held) *out_held = false; - if (g.ActiveId == id) SetActiveID(0); + if (g.ActiveId == id) ClearActiveID(); return false; } @@ -5564,14 +5569,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0])) { pressed = true; - SetActiveID(0); + ClearActiveID(); FocusWindow(window); } if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0]) { if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps pressed = true; - SetActiveID(0); + ClearActiveID(); } // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). @@ -5593,7 +5598,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease)) if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps pressed = true; - SetActiveID(0); + ClearActiveID(); } } @@ -6558,7 +6563,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v } else { - SetActiveID(0); + ClearActiveID(); } } @@ -6874,7 +6879,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s } else { - SetActiveID(0); + ClearActiveID(); } } @@ -7777,7 +7782,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 { // Release focus when we click outside if (g.ActiveId == id) - SetActiveID(0); + ClearActiveID(); } bool value_changed = false; @@ -7879,7 +7884,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) { - SetActiveID(0); + ClearActiveID(); enter_pressed = true; } else if (is_editable) @@ -7895,7 +7900,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 if (InputTextFilterCharacter(&c, flags, callback, user_data)) edit_state.OnKeyPressed((int)c); } - else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; } + else if (IsKeyPressedMap(ImGuiKey_Escape)) { ClearActiveID(); cancel_edit = true; } else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } @@ -8490,7 +8495,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi SetHoveredID(id); if (g.IO.MouseClicked[0]) { - SetActiveID(0); + ClearActiveID(); if (IsPopupOpen(id)) { ClosePopup(id); @@ -8539,7 +8544,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi item_text = "*Unknown item*"; if (Selectable(item_text, item_selected)) { - SetActiveID(0); + ClearActiveID(); value_changed = true; *current_item = i; } diff --git a/imgui_internal.h b/imgui_internal.h index ff188b0f..5e189846 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -710,6 +710,7 @@ namespace ImGui IMGUI_API void EndFrame(); // Ends the ImGui frame. Automatically called by Render()! you most likely don't need to ever call that yourself directly. If you don't need to render you can call EndFrame() but you'll have wasted CPU already. If you don't need to render, don't create any windows instead! IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void ClearActiveID(); IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); From b8043d3ee5622e55408119dc7023f2056755bb52 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 14 Jan 2017 13:47:16 +0100 Subject: [PATCH 396/400] Internal: Renamed ImLoadFileToMemory to ImFileLoadToMemory to be consistent with ImFileOpen + fix mismatching .h name (#917) --- imgui.cpp | 4 ++-- imgui_draw.cpp | 2 +- imgui_internal.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c7b16b26..cd1c1201 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1311,7 +1311,7 @@ FILE* ImFileOpen(const char* filename, const char* mode) // Load file content into memory // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree() -void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes) +void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes) { IM_ASSERT(filename && file_open_mode); if (out_file_size) @@ -2462,7 +2462,7 @@ static void LoadIniSettingsFromDisk(const char* ini_filename) return; int file_size; - char* file_data = (char*)ImLoadFileToMemory(ini_filename, "rb", &file_size, 1); + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_size, 1); if (!file_data) return; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a1d58c0e..03b679d0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1195,7 +1195,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { int data_size = 0; - void* data = ImLoadFileToMemory(filename, "rb", &data_size, 0); + void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); if (!data) { IM_ASSERT(0); // Could not load file. diff --git a/imgui_internal.h b/imgui_internal.h index 5e189846..effc5ce7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -88,8 +88,8 @@ IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, cons // Helpers: Misc IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings -IMGUI_API void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); -IMGUI_API FILE* ImOpenFile(const char* filename, const char* file_open_mode); +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); +IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); IMGUI_API bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c); static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; } static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } From 8e8117c7b1297e12c3a2c6e4ab807e62fa0cd5c1 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 21 Jan 2017 19:23:47 +0100 Subject: [PATCH 397/400] stb_truetype update (with OpenType, Type 2 font handling) (#976) --- stb_truetype.h | 765 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 748 insertions(+), 17 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 88a2da16..92b9a875 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v1.12 - public domain +// stb_truetype.h - v1.14 - public domain // authored from 2009-2016 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: @@ -20,10 +20,12 @@ // // Mikko Mononen: compound shape support, more cmap formats // Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling // // Misc other: // Ryan Gordon // Simon Glass +// github:IntellectualKitty // // Bug/warning reports/fixes: // "Zer" on mollyrocket (with fix) @@ -51,6 +53,7 @@ // // VERSION HISTORY // +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts, num-fonts-in-TTC function // 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual // 1.11 (2016-04-02) fix unused-variable warning // 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef @@ -95,7 +98,8 @@ // // "Load" a font file from a memory buffer (you have to keep the buffer loaded) // stbtt_InitFont() -// stbtt_GetFontOffsetForIndex() -- use for TTC font collections +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections // // Render a unicode codepoint to a bitmap // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap @@ -453,6 +457,14 @@ int main(int arg, char **argv) extern "C" { #endif +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + ////////////////////////////////////////////////////////////////////////////// // // TEXTURE BAKING API @@ -522,7 +534,7 @@ typedef struct stbrp_rect stbrp_rect; STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); // Initializes a packing context stored in the passed-in stbtt_pack_context. // Future calls using this context will pack characters into the bitmap passed -// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is // the distance from one row to the next (or 0 to mean they are packed tightly // together). "padding" is the amount of padding to leave between each // character (normally you want '1' for bitmaps you'll use as textures with @@ -621,14 +633,19 @@ struct stbtt_pack_context { // // +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // Each .ttf/.ttc file may have more than one font. Each font has a sequential // index number starting from 0. Call this function to get the font offset for // a given index; it returns -1 if the index is out of range. A regular .ttf // file will only define one font and it always be at offset 0, so it will -// return '0' for index 0, and -1 for all other indices. You can just skip -// this step if you know it's that kind of font. - +// return '0' for index 0, and -1 for all other indices. // The following structure is defined publically so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. @@ -643,6 +660,13 @@ struct stbtt_fontinfo int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf int index_map; // a cmap mapping for our chosen character encoding int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict }; STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); @@ -720,7 +744,8 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, in enum { STBTT_vmove=1, STBTT_vline, - STBTT_vcurve + STBTT_vcurve, + STBTT_vcubic }; #endif @@ -729,7 +754,7 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, in #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file typedef struct { - stbtt_vertex_type x,y,cx,cy; + stbtt_vertex_type x,y,cx,cy,cx1,cy1; unsigned char type,padding; } stbtt_vertex; #endif @@ -951,6 +976,152 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS #define STBTT__NOTUSED(v) (void)sizeof(v) #endif +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + ////////////////////////////////////////////////////////////////////////// // // accessors to parse data from file @@ -978,6 +1149,7 @@ static int stbtt__isfont(stbtt_uint8 *font) if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts return 0; } @@ -1014,6 +1186,35 @@ static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, return -1; } +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) { stbtt_uint32 cmap, t; @@ -1021,6 +1222,7 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in info->data = data; info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); cmap = stbtt__find_table(data, fontstart, "cmap"); // required info->loca = stbtt__find_table(data, fontstart, "loca"); // required @@ -1029,8 +1231,61 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required info->kern = stbtt__find_table(data, fontstart, "kern"); // not required - if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) + + if (!cmap || !info->head || !info->hhea || !info->hmtx) return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } t = stbtt__find_table(data, fontstart, "maxp"); if (t) @@ -1181,6 +1436,8 @@ static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) { int g1,g2; + STBTT_assert(!info->cff.size); + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format @@ -1195,15 +1452,21 @@ static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) return g1==g2 ? -1 : g1; // if length is 0, return -1 } +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) { - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } return 1; } @@ -1215,7 +1478,10 @@ STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, i STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) { stbtt_int16 numberOfContours; - int g = stbtt__GetGlyfOffset(info, glyph_index); + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); if (g < 0) return 1; numberOfContours = ttSHORT(info->data + g); return numberOfContours == 0; @@ -1237,7 +1503,7 @@ static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_ return num_vertices; } -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) { stbtt_int16 numberOfContours; stbtt_uint8 *endPtsOfContours; @@ -1463,6 +1729,416 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s return num_vertices; } +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // fallthrough + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) { + *x0 = r ? c.min_x : 0; + *y0 = r ? c.min_y : 0; + *x1 = r ? c.max_x : 0; + *y1 = r ? c.max_y : 0; + } + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) { stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); @@ -2333,6 +3009,48 @@ static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x return 1; } +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + // returns number of contours static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) { @@ -2389,6 +3107,14 @@ static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, objspace_flatness_squared, 0); x = vertices[i].x, y = vertices[i].y; break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; } } (*contour_lengths)[n] = num_points - start; @@ -3214,6 +3940,11 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); } +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) { return stbtt_InitFont_internal(info, (unsigned char *) data, offset); From a7cf369e71e0911773e8c43d7c565eb3c0386c4d Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 28 Jan 2017 23:14:35 +0100 Subject: [PATCH 398/400] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c352696..c1068990 100644 --- a/README.md +++ b/README.md @@ -84,12 +84,12 @@ Gallery See the [Screenshots Thread](https://github.com/ocornut/imgui/issues/123) for some user creations. ![screenshot 1](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_01.png) +[![screenshot game](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v149/gallery_TheDragonsTrap-01-thumb.jpg)](https://cloud.githubusercontent.com/assets/8225057/20628927/33e14cac-b329-11e6-80f6-9524e93b048a.png) ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_02.png) -[![profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler-880.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler.png) +[![screenshot profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler-880.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler.png) -![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_01.png) -![screenshot 3](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_02.png) +![screenshot 3](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_01.png) ![screenshot 4](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_03.png) ![screenshot 5](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v140/test_window_05_menus.png) ![screenshot 6](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/skinning_sample_02.png) From 4653197ca43a0b4302ac9b94b82d6e2c19f3e39a Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 28 Jan 2017 23:26:25 +0100 Subject: [PATCH 399/400] Update README, kinder --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c1068990..68d57ee7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Your code passes mouse/keyboard inputs and settings to ImGui (see example applic ImGui outputs vertex buffers and simple command-lists that you can render in your application. The number of draw calls and state changes is typically very small. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase. -_A common misunderstanding is that some people think immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes, as the gui functions as called by the user. Some lazy IMGUI-style librairies may work this way but this is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are rather optimal and you can render them later, in your app or even remotely._ +_A common misunderstanding is to think that immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes, as the gui functions as called by the user. This is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are decently optimal and you can render them later, in your app or even remotely._ ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. @@ -46,7 +46,9 @@ You should be able to build the examples from sources (tested on Windows/Mac/Lin Bindings -------- -_NB: those third-party bindings may be more or less maintained, more or less close to the spirit of original API. People who create language bindings sometimes haven't used the C++ API themselves. ImGui was designed with C++ in mind and some of the subtleties may be lost in translation with other languages. If your language supports it, I would suggest replicating the function overloading and default parameters used in the original, else the API may be harder to use. In doubt, always check the original C++ version first!_ +_NB: those third-party bindings may be more or less maintained, more or less close to the spirit of original API and therefore I cannot give much guarantee about them. People who create language bindings sometimes haven't used the C++ API themselves (for the good reason that they aren't C++ users). ImGui was designed with C++ in mind and some of the subtleties may be lost in translation with other languages. If your language supports it, I would suggest replicating the function overloading and default parameters used in the original, else the API may be harder to use. In doubt, please check the original C++ version first!_ + +_Integrating Dear ImGui within your custom engine is a matter of wiring mouse/keyboard inputs and providing a render function that can bind a texture and render simple textured triangles. The examples/ folder is populated with applications doing just that. If you are an experienced programmer it should take you less than an hour to integrate Dear ImGui in your custom engine, but make sure to spend time reading the FAQ, the comments and other documentation!_ Languages: - cimgui: thin c-api wrapper for ImGui https://github.com/Extrawurst/cimgui From 6384eee34f08cb7eab8d835043e1738e4adcdf75 Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Jan 2017 16:52:52 +0100 Subject: [PATCH 400/400] Minor comments (#998) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 9d84a94f..2d79df00 100644 --- a/imgui.h +++ b/imgui.h @@ -118,7 +118,7 @@ namespace ImGui IMGUI_API void ShowUserGuide(); // help block IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block. you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) IMGUI_API void ShowTestWindow(bool* p_open = NULL); // test window demonstrating ImGui features - IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // metrics window for debugging ImGui + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // metrics window for debugging ImGui (browse draw commands, individual vertices, window list, etc.) // Window IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // push window to the stack and start appending to it. see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_open' creates a widget on the upper-right to close the window (which sets your bool to false).