From 8b2d449b165f2214a088f8d0cd8a20b684e99787 Mon Sep 17 00:00:00 2001 From: thedmd Date: Sun, 19 Nov 2017 21:00:38 +0100 Subject: [PATCH 01/30] Add ShadeVertsLinearUV() --- imgui_draw.cpp | 24 ++++++++++++++++++++++++ imgui_internal.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8718e978..5d8cc5d9 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1226,6 +1226,30 @@ void ImGui::ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_sta } } +// Distribute UV over (a, b) rectangle +void ImGui::ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) +{ + const ImVec2 size = b - a; + const ImVec2 uv_size = uv_b - uv_a; + const ImVec2 scale = ImVec2( + size.x ? (uv_size.x / size.x) : 0.0f, + size.y ? (uv_size.y / size.y) : 0.0f); + + if (clamp) + { + const ImVec2 min = ImMin(uv_a, uv_b); + const ImVec2 max = ImMax(uv_a, uv_b); + + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); + } + else + { + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); + } +} + //----------------------------------------------------------------------------- // ImFontConfig //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 6a5c24aa..f9c9a7d4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -155,6 +155,7 @@ static inline ImVec2 ImFloor(const ImVec2& v) static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } +static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.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. @@ -873,6 +874,7 @@ namespace ImGui // Shade functions IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); IMGUI_API void ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x); + IMGUI_API void ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); } // namespace ImGui From 79f07f6ff040f6bfbf6b86320bf417f1d495966b Mon Sep 17 00:00:00 2001 From: thedmd Date: Sun, 19 Nov 2017 21:48:13 +0100 Subject: [PATCH 02/30] Add AddImageRounded() to ImDrawList --- imgui.h | 2 ++ imgui_draw.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/imgui.h b/imgui.h index 98e016bf..b1bba790 100644 --- a/imgui.h +++ b/imgui.h @@ -1308,6 +1308,7 @@ struct ImDrawList 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); IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF); IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,0), const ImVec2& uv_c = ImVec2(1,1), const ImVec2& uv_d = ImVec2(0,1), ImU32 col = 0xFFFFFFFF); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, float rounding, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF, int rounding_corners = ~0); IMGUI_API void AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness, bool anti_aliased); IMGUI_API void AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col, bool anti_aliased); IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); @@ -1347,6 +1348,7 @@ struct ImDrawList 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(); + IMGUI_API void PrimDistributeUV(ImDrawVert* start, ImDrawVert* end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); }; // All draw data to render an ImGui frame diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5d8cc5d9..e3098f77 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1152,6 +1152,41 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, cons PopTextureID(); } +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, float rounding, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, int rounding_corners) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (rounding <= 0.0f) + { + AddImage(user_texture_id, a, b, uv_a, uv_b, col); + return; + } + + // FIXME-OPT: This is wasting draw calls. + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + if (rounding > 0.0f && rounding_corners != 0) + { + size_t startIndex = VtxBuffer.size(); + PathRect(a, b, rounding, rounding_corners); + PathFillConvex(col); + size_t endIndex = VtxBuffer.size(); + + ImGui::ShadeVertsLinearUV(VtxBuffer.Data + startIndex, VtxBuffer.Data + endIndex, a, b, uv_a, uv_b, true); + } + else + { + PrimReserve(6, 4); + PrimRectUV(a, b, uv_a, uv_b, col); + } + + if (push_texture_id) + PopTextureID(); +} + //----------------------------------------------------------------------------- // ImDrawData //----------------------------------------------------------------------------- From e996286c38ff580f0c80c3b22775c785660fa3b6 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 12:40:38 +0100 Subject: [PATCH 03/30] Todo list update --- TODO.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/TODO.txt b/TODO.txt index c305a411..1271d346 100644 --- a/TODO.txt +++ b/TODO.txt @@ -24,7 +24,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd. - window: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - window: expose contents size. (#1045) + - window: resize from borders and/or all corners. (#822) - window: GetWindowSize() returns (0,0) when not calculated? (#1045) + - window: refactor IsWindowFocused(), merge all three existing variants, add flags, similar to #1382. - window: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. !- scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet. - scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y). (2017-08-20: can't repro) @@ -35,7 +37,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - drawlist: 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). - drawlist: avoid passing null (-9999,+9999) rectangle to end-user, instead perhaps pass rectangle based on io.DisplaySize? - drawlist: primtiives/helpers to manipulate vertices post submission, so e.g. a quad/rect can be resized to fit later submitted content, _without_ using the ChannelSplit api - + - drawlist: non-AA strokes have gaps between points (#593, #288), especially RenderCheckmark(). + - main: considering adding an Init() function? some constructs are awkward in the implementation because of the lack of them. - main: find a way to preserve relative orders of multiple reappearing windows (so an app toggling between "modes" e.g. fullscreen vs all tools) won't lose relative ordering. - 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 @@ -163,9 +166,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - shortcuts: programmatically access shortcuts "Focus("&Save")) - menus: menubars: main menu-bar could affect clamping of windows position (~ akin to modifying DisplayMin) + - text: selectable text (for copy) as a generic feature (ItemFlags?) - text: proper alignment options in imgui_internal.h - text wrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (#249) - text: it's currently impossible to have a window title with "##". perhaps an official workaround would be nice. \ style inhibitor? non-visible ascii code to insert between #? + - text link/url button: underlined. should api expose an ID or use text contents as ID? which colors enum to use? - tree node / optimization: avoid formatting when clipped. - tree node: tree-node/header right-most side doesn't take account of horizontal scrolling. @@ -207,6 +212,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - pie menus patterns (#434) - markup: simple markup language for color change? + - font: free the Alpha buffer if user only requested RGBA. !- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions). - font: better vertical centering (based e.g on height of lowercase 'x'?). currently Roboto-Medium size 16 px isn't currently centered. - font: enforce monospace through ImFontConfig (for icons?) + create dual ImFont output from same input, reusing rasterized data but with different glyphs/AdvanceX @@ -228,6 +234,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - nav: integrate navigation branch into master. (#787) - nav: integrate/design keyboard controls. - nav: once tab should go through most/all widgets (in submission order?) + - nav: currently cannot access menubar of a child window with Alt/menu key. - nav: esc/enter default behavior for popups, e.g. be able to mark an "ok" or "cancel" button that would get triggered by those keys. - 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) @@ -236,7 +243,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - inputs: allow to pass explicit double-clicks if that's the only thing the user's backend can get them. (e.g. for windows by the CS_DBLCLKS style). - inputs: support track pad style scrolling & slider edit. - - misc: make the ImGuiCond values linear (non-power-of-two). internal storage for ImGuiWindow can use integers to combine into flags. + - misc: idle refresh: expose cursor blink animation timer for backend to be able to lower framerate. + - misc: make the ImGuiCond values linear (non-power-of-two). internal storage for ImGuiWindow can use integers to combine into flags (Why?) - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - misc: provide HoveredTime and ActivatedTime to ease the creation of animations. - misc: fix for compilation settings where stdcall isn't the default (e.g. vectorcall) (#1230) From 8c0f2e49466ad9d5e78e25aa05a61023a1fa2da4 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 13:05:50 +0100 Subject: [PATCH 04/30] Added comment to help people dealing with 58345b11e1a999ad3fb562a24aade7c6944e5a02 breakage (#707) --- imgui.h | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.h b/imgui.h index 98e016bf..de09567b 100644 --- a/imgui.h +++ b/imgui.h @@ -659,6 +659,7 @@ enum ImGuiCol_ // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //, ImGuiCol_ComboBg = ImGuiCol_PopupBg // ComboBg has been merged with PopupBg, so a redirect isn't accurate. , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg, ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive #endif }; From 7f447c8270e2baaa9dc08f98a3b4ecba42de28e8 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 13:16:57 +0100 Subject: [PATCH 05/30] Color picker: Tweak vertex shading code, since we aren't shading between PrimReserve and PrimVert the code can be expressed more naturally. (#346) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ca13fcdb..234d77a9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10040,14 +10040,15 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl { const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps; const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; - int vert_start_idx = draw_list->_VtxCurrentIdx; + const int vert_start_idx = draw_list->VtxBuffer.Size; draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness); + const int vert_end_idx = draw_list->VtxBuffer.Size; // Paint colors over existing vertices ImVec2 gradient_p0(wheel_center.x + cosf(a0) * wheel_r_inner, wheel_center.y + sinf(a0) * wheel_r_inner); ImVec2 gradient_p1(wheel_center.x + cosf(a1) * wheel_r_inner, wheel_center.y + sinf(a1) * wheel_r_inner); - ShadeVertsLinearColorGradientKeepAlpha(draw_list->_VtxWritePtr - (draw_list->_VtxCurrentIdx - vert_start_idx), draw_list->_VtxWritePtr, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]); + ShadeVertsLinearColorGradientKeepAlpha(draw_list->VtxBuffer.Data + vert_start_idx, draw_list->VtxBuffer.Data + vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]); } // Render Cursor + preview on Hue Wheel From 3c5e64db782940588e5d7b61e05552126e85775b Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 13:30:25 +0100 Subject: [PATCH 06/30] Demo: Tweaked Image() code. --- imgui_demo.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7bf92e34..a1e8b083 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -539,7 +539,6 @@ void ImGui::ShowTestWindow(bool* p_open) if (ImGui::TreeNode("Images")) { ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); - ImVec2 tex_screen_pos = ImGui::GetCursorScreenPos(); ImGuiIO& io = ImGui::GetIO(); // Here we are grabbing the font texture because that's the only one we have access to inside the demo code. @@ -549,23 +548,24 @@ void ImGui::ShowTestWindow(bool* p_open) // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc. // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this. // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). - ImTextureID tex_id = io.Fonts->TexID; - float tex_w = (float)io.Fonts->TexWidth; - float tex_h = (float)io.Fonts->TexHeight; + ImTextureID my_tex_id = io.Fonts->TexID; + float my_tex_w = (float)io.Fonts->TexWidth; + float my_tex_h = (float)io.Fonts->TexHeight; - ImGui::Text("%.0fx%.0f", tex_w, tex_h); - ImGui::Image(tex_id, ImVec2(tex_w, tex_h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); + ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128)); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); float focus_sz = 32.0f; - float focus_x = io.MousePos.x - tex_screen_pos.x - focus_sz * 0.5f; if (focus_x < 0.0f) focus_x = 0.0f; else if (focus_x > tex_w - focus_sz) focus_x = tex_w - focus_sz; - float focus_y = io.MousePos.y - tex_screen_pos.y - focus_sz * 0.5f; if (focus_y < 0.0f) focus_y = 0.0f; else if (focus_y > tex_h - focus_sz) focus_y = tex_h - focus_sz; + float focus_x = io.MousePos.x - pos.x - focus_sz * 0.5f; if (focus_x < 0.0f) focus_x = 0.0f; else if (focus_x > my_tex_w - focus_sz) focus_x = my_tex_w - focus_sz; + float focus_y = io.MousePos.y - pos.y - focus_sz * 0.5f; if (focus_y < 0.0f) focus_y = 0.0f; else if (focus_y > my_tex_h - focus_sz) focus_y = my_tex_h - focus_sz; ImGui::Text("Min: (%.2f, %.2f)", focus_x, focus_y); ImGui::Text("Max: (%.2f, %.2f)", focus_x + focus_sz, focus_y + focus_sz); - ImVec2 uv0 = ImVec2((focus_x) / tex_w, (focus_y) / tex_h); - ImVec2 uv1 = ImVec2((focus_x + focus_sz) / tex_w, (focus_y + focus_sz) / tex_h); - ImGui::Image(tex_id, ImVec2(128,128), uv0, uv1, ImColor(255,255,255,255), ImColor(255,255,255,128)); + ImVec2 uv0 = ImVec2((focus_x) / my_tex_w, (focus_y) / my_tex_h); + ImVec2 uv1 = ImVec2((focus_x + focus_sz) / my_tex_w, (focus_y + focus_sz) / my_tex_h); + ImGui::Image(my_tex_id, ImVec2(128,128), uv0, uv1, ImColor(255,255,255,255), ImColor(255,255,255,128)); ImGui::EndTooltip(); } ImGui::TextWrapped("And now some textured buttons.."); @@ -574,7 +574,7 @@ void ImGui::ShowTestWindow(bool* p_open) { 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))) + if (ImGui::ImageButton(my_tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/my_tex_w,32/my_tex_h), frame_padding, ImColor(0,0,0,255))) pressed_count += 1; ImGui::PopID(); ImGui::SameLine(); From 31683cfe343ceed744f02e76522a783862abb499 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 13:31:40 +0100 Subject: [PATCH 07/30] ImDrawList::AddImageRounded: removed PrimDistributeUV declaration, fixed coding style, restored argument order from original PR. (#845) --- imgui.h | 3 +-- imgui_draw.cpp | 25 +++++++------------------ 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/imgui.h b/imgui.h index d182660a..3f760be1 100644 --- a/imgui.h +++ b/imgui.h @@ -1309,7 +1309,7 @@ struct ImDrawList 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); IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF); IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,0), const ImVec2& uv_c = ImVec2(1,1), const ImVec2& uv_d = ImVec2(0,1), ImU32 col = 0xFFFFFFFF); - IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, float rounding, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF, int rounding_corners = ~0); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ~0); IMGUI_API void AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness, bool anti_aliased); IMGUI_API void AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col, bool anti_aliased); IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); @@ -1349,7 +1349,6 @@ struct ImDrawList 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(); - IMGUI_API void PrimDistributeUV(ImDrawVert* start, ImDrawVert* end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); }; // All draw data to render an ImGui frame diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e3098f77..5dd9581e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1124,7 +1124,6 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const Im if ((col & IM_COL32_A_MASK) == 0) return; - // FIXME-OPT: This is wasting draw calls. const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); if (push_texture_id) PushTextureID(user_texture_id); @@ -1152,36 +1151,26 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, cons PopTextureID(); } -void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, float rounding, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, int rounding_corners) +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners) { if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding <= 0.0f) + if (rounding <= 0.0f || (rounding_corners & ImGuiCorner_All) == 0) { AddImage(user_texture_id, a, b, uv_a, uv_b, col); return; } - // FIXME-OPT: This is wasting draw calls. const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); if (push_texture_id) PushTextureID(user_texture_id); - if (rounding > 0.0f && rounding_corners != 0) - { - size_t startIndex = VtxBuffer.size(); - PathRect(a, b, rounding, rounding_corners); - PathFillConvex(col); - size_t endIndex = VtxBuffer.size(); - - ImGui::ShadeVertsLinearUV(VtxBuffer.Data + startIndex, VtxBuffer.Data + endIndex, a, b, uv_a, uv_b, true); - } - else - { - PrimReserve(6, 4); - PrimRectUV(a, b, uv_a, uv_b, col); - } + int vert_start_idx = VtxBuffer.Size; + PathRect(a, b, rounding, rounding_corners); + PathFillConvex(col); + int vert_end_idx = VtxBuffer.Size; + ImGui::ShadeVertsLinearUV(VtxBuffer.Data + vert_start_idx, VtxBuffer.Data + vert_end_idx, a, b, uv_a, uv_b, true); if (push_texture_id) PopTextureID(); From 3f5b2a3fe353ff29b1b15334964aaec4e7dff576 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 13:53:16 +0100 Subject: [PATCH 08/30] Exposed ImDrawCornerFlags, replaced occurences of ~0 with an explicit ImDrawCornerFlags_All. Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). --- imgui.cpp | 30 +++++++++++++++--------------- imgui.h | 22 ++++++++++++++++++---- imgui_demo.cpp | 6 ++++-- imgui_draw.cpp | 19 +++++++------------ imgui_internal.h | 9 --------- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 234d77a9..0754dc1d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3084,8 +3084,8 @@ void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, const float border_size = g.Style.FrameBorderSize; if (border && border_size > 0.0f) { - window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ~0, border_size); - window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ~0, border_size); + window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); } } @@ -3096,8 +3096,8 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) const float border_size = g.Style.FrameBorderSize; if (border_size > 0.0f) { - window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ~0, border_size); - window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ~0, border_size); + window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); } } @@ -4458,18 +4458,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Window background, Default Alpha ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); - window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImGuiCorner_All : ImGuiCorner_BotLeft|ImGuiCorner_BotRight); + window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); // Title bar const bool is_focused = g.NavWindow && window->RootNonPopupWindow == g.NavWindow->RootNonPopupWindow; if (!(flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32(is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, ImGuiCorner_TopLeft|ImGuiCorner_TopRight); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32(is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, ImDrawCornerFlags_Top); // 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, ImGuiCorner_TopLeft|ImGuiCorner_TopRight); + window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); if (style.FrameBorderSize > 0.0f) window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } @@ -4493,7 +4493,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Borders if (window_border_size > 0.0f) - window->DrawList->AddRect(window->Pos, window->Pos+window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ~0, window_border_size); + window->DrawList->AddRect(window->Pos, window->Pos+window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size); if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar)) window->DrawList->AddLine(title_bar_rect.GetBL()+ImVec2(1,-1), title_bar_rect.GetBR()+ImVec2(-1,-1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } @@ -4730,9 +4730,9 @@ void ImGui::Scrollbar(ImGuiLayoutType direction) int window_rounding_corners; if (horizontal) - window_rounding_corners = ImGuiCorner_BotLeft | (other_scrollbar ? 0 : ImGuiCorner_BotRight); + window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); else - window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImGuiCorner_TopRight : 0) | (other_scrollbar ? 0 : ImGuiCorner_BotRight); + window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners); bb.Expand(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))); @@ -9440,8 +9440,8 @@ void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU if (x2 <= x1) continue; int rounding_corners_flags_cell = 0; - if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImGuiCorner_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImGuiCorner_TopRight; } - if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImGuiCorner_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImGuiCorner_BotRight; } + if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } rounding_corners_flags_cell &= rounding_corners_flags; window->DrawList->AddRectFilled(ImVec2(x1,y1), ImVec2(x2,y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); } @@ -9504,8 +9504,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col.w < 1.0f) { float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f); - RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col), grid_step, ImVec2(-grid_step + off, off), rounding, ImGuiCorner_TopRight|ImGuiCorner_BotRight); - window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_without_alpha), rounding, ImGuiCorner_TopLeft|ImGuiCorner_BotLeft); + RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft); } else { @@ -9514,7 +9514,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (col_source.w < 1.0f) RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); else - window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ~0); + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All); } if (g.Style.FrameBorderSize > 0.0f) RenderFrameBorder(bb.Min, bb.Max, rounding); diff --git a/imgui.h b/imgui.h index 3f760be1..319e76b0 100644 --- a/imgui.h +++ b/imgui.h @@ -76,6 +76,7 @@ typedef int ImGuiStyleVar; // enum: a variable identifier for styling typedef int ImGuiKey; // enum: a key identifier (ImGui-side enum) // enum ImGuiKey_ typedef int ImGuiMouseCursor; // enum: a mouse cursor identifier // enum ImGuiMouseCursor_ typedef int ImGuiCond; // enum: a condition for Set*() // enum ImGuiCond_ +typedef int ImDrawCornerFlags; // flags: corner flags for AddRect*() etc. // enum ImDrawCornerFlags_ typedef int ImGuiColorEditFlags; // flags: color edit flags for Color*() // enum ImGuiColorEditFlags_ typedef int ImGuiWindowFlags; // flags: window flags for Begin*() // enum ImGuiWindowFlags_ typedef int ImGuiColumnsFlags; // flags: for *Columns*() // enum ImGuiColumnsFlags_ @@ -1258,6 +1259,19 @@ struct ImDrawChannel ImVector IdxBuffer; }; +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 + ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 + ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 + ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA + ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience +}; + // Draw command list // This is the low-level list of polygons that ImGui functions are filling. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. // At the moment, each ImGui window contains its own ImDrawList but they could potentially be merged in the future. @@ -1296,8 +1310,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_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 AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All, 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 = ImDrawCornerFlags_All); // 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); @@ -1309,7 +1323,7 @@ struct ImDrawList 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); IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF); IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,0), const ImVec2& uv_c = ImVec2(1,1), const ImVec2& uv_d = ImVec2(0,1), ImU32 col = 0xFFFFFFFF); - IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ~0); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ImDrawCornerFlags_All); IMGUI_API void AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness, bool anti_aliased); IMGUI_API void AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col, bool anti_aliased); IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); @@ -1323,7 +1337,7 @@ struct ImDrawList 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 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_flags = ~0); // rounding_corners_flags: 4-bits corresponding to which corner to round + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All); // 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_demo.cpp b/imgui_demo.cpp index a1e8b083..b1fefba4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2315,8 +2315,9 @@ static void ShowExampleAppCustomRendering(bool* p_open) { 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->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, thickness); x += sz+spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, thickness); x += sz+spacing; + draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, 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; @@ -2328,6 +2329,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) 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->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight); 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 5dd9581e..28d25e2d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -931,13 +931,8 @@ void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImV void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners) { - const int corners_top = ImGuiCorner_TopLeft | ImGuiCorner_TopRight; - const int corners_bottom = ImGuiCorner_BotLeft | ImGuiCorner_BotRight; - const int corners_left = ImGuiCorner_TopLeft | ImGuiCorner_BotLeft; - const int corners_right = ImGuiCorner_TopRight | ImGuiCorner_BotRight; - - rounding = ImMin(rounding, fabsf(b.x - a.x) * ( ((rounding_corners & corners_top) == corners_top) || ((rounding_corners & corners_bottom) == corners_bottom) ? 0.5f : 1.0f ) - 1.0f); - rounding = ImMin(rounding, fabsf(b.y - a.y) * ( ((rounding_corners & corners_left) == corners_left) || ((rounding_corners & corners_right) == corners_right) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, fabsf(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, fabsf(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); if (rounding <= 0.0f || rounding_corners == 0) { @@ -948,10 +943,10 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int } else { - const float rounding_tl = (rounding_corners & ImGuiCorner_TopLeft) ? rounding : 0.0f; - const float rounding_tr = (rounding_corners & ImGuiCorner_TopRight) ? rounding : 0.0f; - const float rounding_br = (rounding_corners & ImGuiCorner_BotRight) ? rounding : 0.0f; - const float rounding_bl = (rounding_corners & ImGuiCorner_BotLeft) ? rounding : 0.0f; + const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; + const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; + const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; + const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); @@ -1156,7 +1151,7 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, c if ((col & IM_COL32_A_MASK) == 0) return; - if (rounding <= 0.0f || (rounding_corners & ImGuiCorner_All) == 0) + if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) { AddImage(user_texture_id, a, b, uv_a, uv_b, col); return; diff --git a/imgui_internal.h b/imgui_internal.h index f9c9a7d4..cf62d915 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -243,15 +243,6 @@ enum ImGuiDir ImGuiDir_Down = 3 }; -enum ImGuiCorner -{ - ImGuiCorner_TopLeft = 1 << 0, // 1 - ImGuiCorner_TopRight = 1 << 1, // 2 - ImGuiCorner_BotRight = 1 << 2, // 4 - ImGuiCorner_BotLeft = 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 195abc3d178525d7d85f0629a6de2e7610692eca Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 15:19:38 +0100 Subject: [PATCH 09/30] Begin: Fix border size latch when rounding uses Child or Popup value. (#707) --- imgui.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0754dc1d..1c185302 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4270,15 +4270,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } } - // Lock window padding so that altering the border sizes for children doesn't have side-effects. - window->WindowPadding = style.WindowPadding; - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup)) && style.WindowBorderSize == 0.0f) - window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + // Lock window rounding, border size and rounding so that altering the border sizes for children doesn't have side-effects. window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; - const ImVec2 window_padding = window->WindowPadding; + window->WindowPadding = style.WindowPadding; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) + window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); const float window_rounding = window->WindowRounding; const float window_border_size = window->WindowBorderSize; + const ImVec2 window_padding = window->WindowPadding; // Calculate auto-fit size, handle automatic resize const ImVec2 size_auto_fit = CalcSizeAutoFit(window); From 302757447aa6f0eed177e6cb33de887242a6355e Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 20 Nov 2017 19:39:27 +0100 Subject: [PATCH 10/30] Internals: Added SplitterBehavior(). (#319) --- imgui.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ imgui_internal.h | 8 ++++++++ 2 files changed, 57 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 1c185302..c074864c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10184,6 +10184,55 @@ void ImGui::VerticalSeparator() LogText(" |"); } +bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; +#ifdef IMGUI_HAS_NAV + window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; +#endif + bool add = ItemAdd(bb, id); + window->DC.ItemFlags = item_flags_backup; + if (!add) + return false; + + bool hovered, held; + ImRect bb_interact = bb; + bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); + ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChilds | ImGuiButtonFlags_AllowOverlapMode); + if (g.ActiveId != id) + SetItemAllowOverlap(); + + if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id)) + SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); + + ImRect bb_render = bb; + if (held) + { + ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min; + float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x; + + // Minimum pane size + if (mouse_delta < min_size1 - *size1) + mouse_delta = min_size1 - *size1; + if (mouse_delta > *size2 - min_size2) + mouse_delta = *size2 - min_size2; + + // Apply resize + *size1 += mouse_delta; + *size2 -= mouse_delta; + bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); + } + + // Render + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + RenderFrame(bb_render.Min, bb_render.Max, col, true, g.Style.FrameRounding); + + return held; +} + void ImGui::Spacing() { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui_internal.h b/imgui_internal.h index cf62d915..e54936a5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -221,6 +221,13 @@ enum ImGuiLayoutType_ ImGuiLayoutType_Horizontal }; +enum ImGuiAxis +{ + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1, +}; + enum ImGuiPlotType { ImGuiPlotType_Lines, @@ -807,6 +814,7 @@ namespace ImGui IMGUI_API void Scrollbar(ImGuiLayoutType direction); IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). not exposed because it is misleading what it doesn't have an effect on regular layout. + IMGUI_API bool SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f); // FIXME-WIP: New Columns API IMGUI_API void BeginColumns(const char* id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). From 176d8fbe747d63ecf282480e258ad9a174816404 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 Nov 2017 11:02:42 +0100 Subject: [PATCH 11/30] Fixed unreferenced variable warnings. --- imgui.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c074864c..02366293 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3747,9 +3747,9 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags ext void ImGui::EndPopup() { - ImGuiWindow* window = GetCurrentWindow(); - IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls - IM_ASSERT(GImGui->CurrentPopupStack.Size > 0); + ImGuiContext& g = *GImGui; (void)g; + IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + IM_ASSERT(g.CurrentPopupStack.Size > 0); End(); } @@ -4278,7 +4278,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); const float window_rounding = window->WindowRounding; const float window_border_size = window->WindowBorderSize; - const ImVec2 window_padding = window->WindowPadding; // Calculate auto-fit size, handle automatic resize const ImVec2 size_auto_fit = CalcSizeAutoFit(window); From 21b456e5678c196c0fe242dc0e82cc22be5d1307 Mon Sep 17 00:00:00 2001 From: Giuseppe Barbieri Date: Wed, 22 Nov 2017 11:19:52 +0100 Subject: [PATCH 12/30] Update imgui.cpp --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 02366293..1d2a5a77 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9717,7 +9717,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag PushItemWidth(w_items_all); if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) { - value_changed |= true; + value_changed = true; char* p = buf; while (*p == '#' || ImCharIsSpace(*p)) p++; From aafa6cece5b7eea039db5c56cb11032d9441be8b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 Nov 2017 11:26:16 +0100 Subject: [PATCH 13/30] Tweak expression to be less weird (how did that ever happen?) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 1d2a5a77..2323dce0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9697,7 +9697,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (n + 1 == components) PushItemWidth(w_item_last); if (flags & ImGuiColorEditFlags_Float) - value_changed |= value_changed_as_float |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); else value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); if (!(flags & ImGuiColorEditFlags_NoOptions)) From 1b2ec35b8ded8399cc3d47642121e090ef353f65 Mon Sep 17 00:00:00 2001 From: Giuseppe Barbieri Date: Wed, 22 Nov 2017 12:58:11 +0100 Subject: [PATCH 14/30] Update imgui_draw.cpp --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 28d25e2d..48101444 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -237,8 +237,8 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); From 7763ab3fcc1f728f35919aae2225c05b084f16c4 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 22 Nov 2017 12:26:50 +0100 Subject: [PATCH 15/30] Menu bar: better software clipping to handle small windows, in particular child window don't have the minimum constraint added in e9a7e73bbaacec886f9b39130428b81b7f95bf16 so we need to render clipped menus better. --- imgui.cpp | 23 ++++++++++++++--------- imgui_internal.h | 1 + 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2323dce0..c1361f73 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4460,16 +4460,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); // Title bar - const bool is_focused = g.NavWindow && window->RootNonPopupWindow == g.NavWindow->RootNonPopupWindow; + const bool window_is_focused = g.NavWindow && window->RootNonPopupWindow == g.NavWindow->RootNonPopupWindow; if (!(flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32(is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, ImDrawCornerFlags_Top); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, ImDrawCornerFlags_Top); // 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, ImDrawCornerFlags_Top); - if (style.FrameBorderSize > 0.0f) + menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. + window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } @@ -9231,14 +9232,18 @@ bool ImGui::BeginMenuBar() if (!(window->Flags & ImGuiWindowFlags_MenuBar)) return false; - ImGuiContext& g = *GImGui; IM_ASSERT(!window->DC.MenuBarAppending); BeginGroup(); // Save position PushID("##menubar"); - ImRect rect = window->MenuBarRect(); - rect.Max.x = ImMax(rect.Min.x, rect.Max.x - g.Style.WindowRounding); - PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->WindowBorderSize + 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); + + // We don't clip with regular window clipping rectangle as it is already set to the area below. However we clip with window full rect. + // We remove 1 worth of rounding to Max.x to that text in long menus don't tend to display over the lower-right rounded area, which looks particularly glitchy. + ImRect bar_rect = window->MenuBarRect(); + ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f)); + clip_rect.ClipWith(window->Rect()); + PushClipRect(clip_rect.Min, clip_rect.Max, false); + + window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffsetX, bar_rect.Min.y);// + g.Style.FramePadding.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.MenuBarAppending = true; AlignTextToFramePadding(); diff --git a/imgui_internal.h b/imgui_internal.h index e54936a5..f155abf7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -746,6 +746,7 @@ public: ImGuiID GetID(const void* ptr); ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); + // We don't use g.FontSize because the window may be != g.CurrentWidow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } From 6bd3b45b34476b77e95874db1934b95e910db189 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 24 Nov 2017 09:23:17 +0100 Subject: [PATCH 16/30] Sisyphus says: tweaked comments about not using old-style OpenGL examples (#1459, #1394 etc.) --- examples/README.txt | 13 +++++++------ examples/opengl2_example/imgui_impl_glfw.cpp | 13 +++++++------ examples/opengl2_example/imgui_impl_glfw.h | 5 +++-- examples/opengl2_example/main.cpp | 5 +++-- imgui.cpp | 3 +-- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 35490b5b..8ec8e752 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -46,12 +46,13 @@ Also note that some setup or GPU drivers may be causing extra lag (possibly by e leaving you with no option but sadness/anger (Intel GPU drivers were reported as such). opengl2_example/ - *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* - GLFW + OpenGL example (old, fixed graphic pipeline). - This is mostly provided as a reference to learn how ImGui integration works, because it is easier to read. - If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything - more complicated, will require your code to reset every single OpenGL attributes to their initial state, - and might confuse your GPU driver. Prefer using opengl3_example. + **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** + **Prefer using the code in the opengl3_example/ folder** + GLFW + OpenGL example (legacy fixed graphic pipeline). + This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. + If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more + complicated, will require your code to reset every single OpenGL attributes to their initial state, and might + confuse your GPU driver. opengl3_example/ GLFW + OpenGL example (programmable pipeline, binding modern functions with GL3W). diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index 52962c19..b6bb56a3 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -1,12 +1,13 @@ -// ImGui GLFW binding with OpenGL +// ImGui GLFW binding with OpenGL (legacy fixed pipeline) // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* -// This is mostly provided as a reference to learn how ImGui integration works, because it is easier to read. -// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything -// more complicated, will require your code to reset every single OpenGL attributes to their initial state, -// and might confuse your GPU driver. Prefer using opengl3_example. +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the opengl3_example/ folder** +// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. +// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more +// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might +// confuse your GPU driver. // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. diff --git a/examples/opengl2_example/imgui_impl_glfw.h b/examples/opengl2_example/imgui_impl_glfw.h index f17833ae..22f910ea 100644 --- a/examples/opengl2_example/imgui_impl_glfw.h +++ b/examples/opengl2_example/imgui_impl_glfw.h @@ -1,8 +1,9 @@ -// ImGui GLFW binding with OpenGL +// ImGui GLFW binding with OpenGL (legacy fixed pipeline) // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the opengl3_example/ folder** // See imgui_impl_glfw.cpp for details. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. diff --git a/examples/opengl2_example/main.cpp b/examples/opengl2_example/main.cpp index 1f3336d2..ed8f1a7b 100644 --- a/examples/opengl2_example/main.cpp +++ b/examples/opengl2_example/main.cpp @@ -1,8 +1,9 @@ -// ImGui - standalone example application for GLFW + OpenGL 2, using fixed pipeline +// ImGui - standalone example application for GLFW + OpenGL2, using legacy fixed pipeline // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the opengl3_example/ folder** // See imgui_impl_glfw.cpp for details. #include diff --git a/imgui.cpp b/imgui.cpp index c1361f73..0c209b67 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -103,8 +103,7 @@ - Add the Dear ImGui source files to your projects, using your preferred build system. It is recommended you build the .cpp files as part of your project and not as a library. - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types. - - See examples/ folder for standalone sample applications. To understand the integration process, you can read examples/opengl2_example/ because - it is short, then switch to the one more appropriate to your use case. + - See examples/ folder for standalone sample applications. - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/. - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. From ef5dd30625913d8aef7083d4bc2f711131f7a86c Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 24 Nov 2017 09:27:45 +0100 Subject: [PATCH 17/30] Sisyphus says: tweaked comments about not using old-style OpenGL examples (#1459, #1394 etc.) --- examples/README.txt | 19 +++++++++++-------- examples/opengl2_example/imgui_impl_glfw.cpp | 2 +- examples/opengl2_example/imgui_impl_glfw.h | 2 +- .../sdl_opengl2_example/imgui_impl_sdl.cpp | 13 +++++++------ examples/sdl_opengl2_example/imgui_impl_sdl.h | 6 +++++- examples/sdl_opengl2_example/main.cpp | 3 ++- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 8ec8e752..1f00756f 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -48,7 +48,7 @@ leaving you with no option but sadness/anger (Intel GPU drivers were reported as opengl2_example/ **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** **Prefer using the code in the opengl3_example/ folder** - GLFW + OpenGL example (legacy fixed graphic pipeline). + GLFW + OpenGL example (legacy, fixed pipeline). This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more complicated, will require your code to reset every single OpenGL attributes to their initial state, and might @@ -57,7 +57,7 @@ opengl2_example/ opengl3_example/ GLFW + OpenGL example (programmable pipeline, binding modern functions with GL3W). This uses more modern OpenGL calls and custom shaders. - Prefer using that if you are using modern OpenGL3/4 in your application. + Prefer using that if you are using modern OpenGL in your application (anything with shaders, vbo, vao, etc.). directx9_example/ DirectX9 example, Windows only. @@ -76,15 +76,18 @@ apple_example/ Synergy keyboard integration is rather hacky. sdl_opengl2_example/ - *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* - SDL2 + OpenGL example (old fixed pipeline). - This is mostly provided as a reference to learn how ImGui integration works, because it is easier to read. - If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything - more complicated, will require your code to reset every single OpenGL attributes to their initial state, - and might confuse your GPU driver. Prefer using sdl_opengl3_example. + **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** + **Prefer using the code in the sdl_opengl3_example/ folder** + SDL2 + OpenGL example (legacy, fixed pipeline). + This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. + If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more + complicated, will require your code to reset every single OpenGL attributes to their initial state, and might + confuse your GPU driver. sdl_opengl3_example/ SDL2 + OpenGL3 example. + This uses more modern OpenGL calls and custom shaders. + Prefer using that if you are using modern OpenGL in your application (anything with shaders, vbo, vao, etc.). allegro5_example/ Allegro 5 example. diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index b6bb56a3..364d9288 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -1,4 +1,4 @@ -// ImGui GLFW binding with OpenGL (legacy fixed pipeline) +// ImGui GLFW binding with OpenGL (legacy, fixed pipeline) // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) diff --git a/examples/opengl2_example/imgui_impl_glfw.h b/examples/opengl2_example/imgui_impl_glfw.h index 22f910ea..d04a84fa 100644 --- a/examples/opengl2_example/imgui_impl_glfw.h +++ b/examples/opengl2_example/imgui_impl_glfw.h @@ -1,4 +1,4 @@ -// ImGui GLFW binding with OpenGL (legacy fixed pipeline) +// ImGui GLFW binding with OpenGL (legacy, fixed pipeline) // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp index 2982f8de..66f3ed5a 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp @@ -1,12 +1,13 @@ -// ImGui SDL2 binding with OpenGL +// ImGui SDL2 binding with OpenGL (legacy, fixed pipeline) // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. // (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* -// This is mostly provided as a reference to learn how ImGui integration works, because it is easier to read. -// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything -// more complicated, will require your code to reset every single OpenGL attributes to their initial state, -// and might confuse your GPU driver. Prefer using sdl_opengl3_example. +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the sdl_opengl3_example/ folder** +// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read. +// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more +// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might +// confuse your GPU driver. // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.h b/examples/sdl_opengl2_example/imgui_impl_sdl.h index ea94f69a..32d7bc0e 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.h +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.h @@ -1,7 +1,11 @@ -// ImGui SDL2 binding with OpenGL +// ImGui SDL2 binding with OpenGL (legacy, fixed pipeline) // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. // (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the sdl_opengl3_example/ folder** +// See imgui_impl_sdl.cpp for details. + // 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_opengl2_example/main.cpp b/examples/sdl_opengl2_example/main.cpp index cfa43e8e..77241a5b 100644 --- a/examples/sdl_opengl2_example/main.cpp +++ b/examples/sdl_opengl2_example/main.cpp @@ -2,7 +2,8 @@ // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. // (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) -// *DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL* +// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** +// **Prefer using the code in the sdl_opengl3_example/ folder** // See imgui_impl_sdl.cpp for details. #include From d9c5d72962b4f88491cf570aaaa2b0ce8e2b6fb9 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 24 Nov 2017 11:26:42 +0100 Subject: [PATCH 18/30] ImGuiStorage: Added BuildSortByKey() helper to rebuild storage from stratch. --- imgui.cpp | 17 +++++++++++++++++ imgui.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 0c209b67..211bd299 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1411,6 +1411,23 @@ static ImVector::iterator LowerBound(ImVectorkey > ((const Pair*)rhs)->key) return +1; + if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1; + return 0; + } + }; + if (Data.Size > 1) + qsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID); +} + int ImGuiStorage::GetInt(ImGuiID key, int default_val) const { ImVector::iterator it = LowerBound(const_cast&>(Data), key); diff --git a/imgui.h b/imgui.h index 319e76b0..4599d705 100644 --- a/imgui.h +++ b/imgui.h @@ -1097,6 +1097,9 @@ struct ImGuiStorage // Use on your own storage if you know only integer are being stored (open/close all tree nodes) IMGUI_API void SetAllInt(int val); + + // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + IMGUI_API void BuildSortByKey(); }; // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used and the corresponding callback is triggered. From 0f955b818d729805300f9e0aed936fa794d71b5b Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 26 Nov 2017 11:44:52 +0100 Subject: [PATCH 19/30] Fixed DroidSans font link (#1460) --- extra_fonts/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra_fonts/README.txt b/extra_fonts/README.txt index a4136083..5d41a6bb 100644 --- a/extra_fonts/README.txt +++ b/extra_fonts/README.txt @@ -153,7 +153,7 @@ DroidSans.ttf Copyright (c) Steve Matteson Apache License, version 2.0 - http://www.google.com/fonts/specimen/Droid+Sans + https://www.fontsquirrel.com/fonts/droid-sans ProggyClean.ttf Copyright (c) 2004, 2005 Tristan Grimmer From 532f564fd325421d11991c21a5e8bdfbb2b1bc26 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 27 Nov 2017 16:55:06 +0100 Subject: [PATCH 20/30] ImGuiTextBuffer: Renamed append() helper to appendf(), appendv() to appendfv(). Added reserve(). --- imgui.cpp | 9 +++++---- imgui.h | 5 +++-- imgui_demo.cpp | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 211bd299..505fa0a8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -213,6 +213,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. + - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. @@ -1643,7 +1644,7 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const #endif // Helper: Text buffer for logging/accumulating text -void ImGuiTextBuffer::appendv(const char* fmt, va_list args) +void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) { va_list args_copy; va_copy(args_copy, args); @@ -1664,11 +1665,11 @@ void ImGuiTextBuffer::appendv(const char* fmt, va_list args) ImFormatStringV(&Buf[write_off - 1], len + 1, fmt, args_copy); } -void ImGuiTextBuffer::append(const char* fmt, ...) +void ImGuiTextBuffer::appendf(const char* fmt, ...) { va_list args; va_start(args, fmt); - appendv(fmt, args); + appendfv(fmt, args); va_end(args); } @@ -2947,7 +2948,7 @@ void ImGui::LogText(const char* fmt, ...) } else { - g.LogClipboard->appendv(fmt, args); + g.LogClipboard->appendfv(fmt, args); } va_end(args); } diff --git a/imgui.h b/imgui.h index 4599d705..309730f2 100644 --- a/imgui.h +++ b/imgui.h @@ -1048,9 +1048,10 @@ struct ImGuiTextBuffer int size() const { return Buf.Size - 1; } bool empty() { return Buf.Size <= 1; } void clear() { Buf.clear(); Buf.push_back(0); } + void reserve(int capacity) { Buf.reserve(capacity); } const char* c_str() const { return Buf.Data; } - IMGUI_API void append(const char* fmt, ...) IM_FMTARGS(2); - IMGUI_API void appendv(const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); + IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); }; // Helper: Simple Key->value storage diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b1fefba4..30a4ce46 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2707,7 +2707,7 @@ struct ExampleAppLog int old_size = Buf.size(); va_list args; va_start(args, fmt); - Buf.appendv(fmt, args); + Buf.appendfv(fmt, args); va_end(args); for (int new_size = Buf.size(); old_size < new_size; old_size++) if (Buf[old_size] == '\n') @@ -2911,7 +2911,7 @@ static void ShowExampleAppLongText(bool* p_open) if (ImGui::Button("Add 1000 lines")) { for (int i = 0; i < 1000; i++) - log.append("%i The quick brown fox jumps over the lazy dog\n", lines+i); + log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i); lines += 1000; } ImGui::BeginChild("Log"); From ade09b9e3c7bbc3e46256fea10b64ce992eec331 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 27 Nov 2017 19:01:40 +0100 Subject: [PATCH 21/30] Settings: Basic internal refactor to have functions for saving from/to memory (not exposed) --- imgui.cpp | 52 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 505fa0a8..fcf3e8c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -646,7 +646,9 @@ static void AddWindowToSortedBuffer(ImVector& out_sort static ImGuiIniData* FindWindowSettings(const char* name); static ImGuiIniData* AddWindowSettings(const char* name); static void LoadIniSettingsFromDisk(const char* ini_filename); +static void LoadIniSettingsFromMemory(const char* buf, const char* buf_end = NULL); static void SaveIniSettingsToDisk(const char* ini_filename); +static void SaveIniSettingsToMemory(ImVector& out_buf); static void MarkIniSettingsDirty(ImGuiWindow* window); static ImRect GetVisibleRect(); @@ -2562,18 +2564,23 @@ static ImGuiIniData* AddWindowSettings(const char* name) // FIXME: Write something less rubbish static void LoadIniSettingsFromDisk(const char* ini_filename) { - ImGuiContext& g = *GImGui; if (!ini_filename) return; - int file_size; char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_size, 1); if (!file_data) return; + LoadIniSettingsFromMemory(file_data, file_data + file_size); + ImGui::MemFree(file_data); +} +static void LoadIniSettingsFromMemory(const char* buf, const char* buf_end) +{ + ImGuiContext& g = *GImGui; + if (!buf_end) + buf_end = buf + strlen(buf); ImGuiIniData* settings = NULL; - const char* buf_end = file_data + file_size; - for (const char* line_start = file_data; line_start < buf_end; ) + for (const char* line_start = buf; line_start < buf_end; ) { const char* line_end = line_start; while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') @@ -2601,8 +2608,6 @@ static void LoadIniSettingsFromDisk(const char* ini_filename) line_start = line_end+1; } - - ImGui::MemFree(file_data); } static void SaveIniSettingsToDisk(const char* ini_filename) @@ -2612,6 +2617,22 @@ static void SaveIniSettingsToDisk(const char* ini_filename) if (!ini_filename) return; + ImVector buf; + SaveIniSettingsToMemory(buf); + + // Write .ini file + FILE* f = ImFileOpen(ini_filename, "wt"); + if (!f) + return; + fwrite(buf.Data, sizeof(char), (size_t)buf.Size, f); + fclose(f); +} + +static void SaveIniSettingsToMemory(ImVector& out_buf) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + // Gather data from windows that were active during this session for (int i = 0; i != g.Windows.Size; i++) { @@ -2626,11 +2647,10 @@ static void SaveIniSettingsToDisk(const char* ini_filename) settings->Collapsed = window->Collapsed; } - // Write .ini file + // Write a buffer // If a window wasn't opened in this session we preserve its settings - FILE* f = ImFileOpen(ini_filename, "wt"); - if (!f) - return; + ImGuiTextBuffer buf; + buf.reserve(g.Settings.Size * 64); // ballpark reserve for (int i = 0; i != g.Settings.Size; i++) { const ImGuiIniData* settings = &g.Settings[i]; @@ -2639,14 +2659,14 @@ static void SaveIniSettingsToDisk(const char* ini_filename) const char* name = settings->Name; if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() name = p; - fprintf(f, "[%s]\n", name); - fprintf(f, "Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); - fprintf(f, "Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); - fprintf(f, "Collapsed=%d\n", settings->Collapsed); - fprintf(f, "\n"); + buf.appendf("[%s]\n", name); + buf.appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); + buf.appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); + buf.appendf("Collapsed=%d\n", settings->Collapsed); + buf.appendf("\n"); } - fclose(f); + out_buf.swap(buf.Buf); } static void MarkIniSettingsDirty(ImGuiWindow* window) From d552cabd15017f61a291787935985b97d2e0380c Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 27 Nov 2017 23:00:27 +0100 Subject: [PATCH 22/30] Settings: Internal renaming of structure and fields names. --- imgui.cpp | 50 +++++++++++++++++++++++++----------------------- imgui_internal.h | 6 +++--- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fcf3e8c3..8b618988 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -643,8 +643,9 @@ static void AddDrawListToRenderList(ImVector& out_rende static void AddWindowToRenderList(ImVector& out_render_list, ImGuiWindow* window); static void AddWindowToSortedBuffer(ImVector& out_sorted_windows, ImGuiWindow* window); -static ImGuiIniData* FindWindowSettings(const char* name); -static ImGuiIniData* AddWindowSettings(const char* name); +static ImGuiSettingsWindow* FindWindowSettings(const char* name); +static ImGuiSettingsWindow* AddWindowSettings(const char* name); + static void LoadIniSettingsFromDisk(const char* ini_filename); static void LoadIniSettingsFromMemory(const char* buf, const char* buf_end = NULL); static void SaveIniSettingsToDisk(const char* ini_filename); @@ -2468,7 +2469,7 @@ void ImGui::Initialize() g.LogClipboard = (ImGuiTextBuffer*)ImGui::MemAlloc(sizeof(ImGuiTextBuffer)); IM_PLACEMENT_NEW(g.LogClipboard) ImGuiTextBuffer(); - IM_ASSERT(g.Settings.empty()); + IM_ASSERT(g.SettingsWindows.empty()); LoadIniSettingsFromDisk(g.IO.IniFilename); g.Initialized = true; } @@ -2503,9 +2504,9 @@ void ImGui::Shutdown() g.HoveredRootWindow = NULL; g.ActiveIdWindow = NULL; g.MovingWindow = NULL; - for (int i = 0; i < g.Settings.Size; i++) - ImGui::MemFree(g.Settings[i].Name); - g.Settings.clear(); + for (int i = 0; i < g.SettingsWindows.Size; i++) + ImGui::MemFree(g.SettingsWindows[i].Name); + g.SettingsWindows.clear(); g.ColorModifiers.clear(); g.StyleModifiers.clear(); g.FontStack.clear(); @@ -2535,29 +2536,30 @@ void ImGui::Shutdown() g.Initialized = false; } -static ImGuiIniData* FindWindowSettings(const char* name) +static ImGuiSettingsWindow* FindWindowSettings(const char* name) { ImGuiContext& g = *GImGui; ImGuiID id = ImHash(name, 0); - for (int i = 0; i != g.Settings.Size; i++) + for (int i = 0; i != g.SettingsWindows.Size; i++) { - ImGuiIniData* ini = &g.Settings[i]; + ImGuiSettingsWindow* ini = &g.SettingsWindows[i]; if (ini->Id == id) return ini; } return NULL; } -static ImGuiIniData* AddWindowSettings(const char* name) +static ImGuiSettingsWindow* 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->Collapsed = false; - ini->Pos = ImVec2(FLT_MAX,FLT_MAX); - ini->Size = ImVec2(0,0); - return ini; + ImGuiContext& g = *GImGui; + g.SettingsWindows.resize(g.SettingsWindows.Size + 1); + ImGuiSettingsWindow* settings = &g.SettingsWindows.back(); + settings->Name = ImStrdup(name); + settings->Id = ImHash(name, 0); + settings->Collapsed = false; + settings->Pos = ImVec2(FLT_MAX,FLT_MAX); + settings->Size = ImVec2(0,0); + return settings; } // Zero-tolerance, poor-man .ini parsing @@ -2579,7 +2581,7 @@ static void LoadIniSettingsFromMemory(const char* buf, const char* buf_end) ImGuiContext& g = *GImGui; if (!buf_end) buf_end = buf + strlen(buf); - ImGuiIniData* settings = NULL; + ImGuiSettingsWindow* settings = NULL; for (const char* line_start = buf; line_start < buf_end; ) { const char* line_end = line_start; @@ -2639,7 +2641,7 @@ static void SaveIniSettingsToMemory(ImVector& out_buf) ImGuiWindow* window = g.Windows[i]; if (window->Flags & ImGuiWindowFlags_NoSavedSettings) continue; - ImGuiIniData* settings = FindWindowSettings(window->Name); + ImGuiSettingsWindow* settings = FindWindowSettings(window->Name); if (!settings) // This will only return NULL in the rare instance where the window was first created with ImGuiWindowFlags_NoSavedSettings then had the flag disabled later on. We don't bind settings in this case (bug #1000). continue; settings->Pos = window->Pos; @@ -2650,10 +2652,10 @@ static void SaveIniSettingsToMemory(ImVector& out_buf) // Write a buffer // If a window wasn't opened in this session we preserve its settings ImGuiTextBuffer buf; - buf.reserve(g.Settings.Size * 64); // ballpark reserve - for (int i = 0; i != g.Settings.Size; i++) + buf.reserve(g.SettingsWindows.Size * 64); // ballpark reserve + for (int i = 0; i != g.SettingsWindows.Size; i++) { - const ImGuiIniData* settings = &g.Settings[i]; + const ImGuiSettingsWindow* settings = &g.SettingsWindows[i]; if (settings->Pos.x == FLT_MAX) continue; const char* name = settings->Name; @@ -4008,7 +4010,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl window->PosFloat = ImVec2(60, 60); window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); - ImGuiIniData* settings = FindWindowSettings(name); + ImGuiSettingsWindow* settings = FindWindowSettings(name); if (!settings) settings = AddWindowSettings(name); else diff --git a/imgui_internal.h b/imgui_internal.h index f155abf7..ed227929 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -38,7 +38,7 @@ struct ImGuiGroupData; struct ImGuiSimpleColumns; struct ImGuiDrawContext; struct ImGuiTextEditState; -struct ImGuiIniData; +struct ImGuiSettingsWindow; struct ImGuiMouseCursorData; struct ImGuiPopupRef; struct ImGuiWindow; @@ -370,7 +370,7 @@ struct IMGUI_API ImGuiTextEditState }; // Data saved in imgui.ini file -struct ImGuiIniData +struct ImGuiSettingsWindow { char* Name; ImGuiID Id; @@ -438,7 +438,7 @@ struct ImGuiContext ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovingWindow; // Track the child window we clicked on to move a window. ImGuiID MovingWindowMoveId; // == MovingWindow->MoveId - ImVector Settings; // .ini Settings + ImVector SettingsWindows; // .ini Settings float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() From 7e2d0d734c477e033fd57a875705dc5ad8571687 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 27 Nov 2017 23:55:42 +0100 Subject: [PATCH 23/30] Settings: basic refactor so that additional data structures can be loaded/saved. Parser/saver is still the minimum viable poor-man parsing. --- imgui.cpp | 182 ++++++++++++++++++++++++++++++----------------- imgui_internal.h | 20 +++++- 2 files changed, 135 insertions(+), 67 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8b618988..41b3b621 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -647,7 +647,7 @@ static ImGuiSettingsWindow* FindWindowSettings(const char* name); static ImGuiSettingsWindow* AddWindowSettings(const char* name); static void LoadIniSettingsFromDisk(const char* ini_filename); -static void LoadIniSettingsFromMemory(const char* buf, const char* buf_end = NULL); +static void LoadIniSettingsFromMemory(const char* buf); static void SaveIniSettingsToDisk(const char* ini_filename); static void SaveIniSettingsToMemory(ImVector& out_buf); static void MarkIniSettingsDirty(ImGuiWindow* window); @@ -924,8 +924,16 @@ void ImStrncpy(char* dst, const char* src, int count) char* ImStrdup(const char *str) { size_t len = strlen(str) + 1; - void* buff = ImGui::MemAlloc(len); - return (char*)memcpy(buff, (const void*)str, len); + void* buf = ImGui::MemAlloc(len); + return (char*)memcpy(buf, (const void*)str, len); +} + +char* ImStrchrRange(const char* str, const char* str_end, char c) +{ + for ( ; str < str_end; str++) + if (*str == c) + return (char*)str; + return NULL; } int ImStrlenW(const ImWchar* str) @@ -2463,12 +2471,75 @@ void ImGui::NewFrame() ImGui::Begin("Debug##Default"); } +static void* SettingsHandlerWindow_ReadOpenEntry(ImGuiContext&, const char* name) +{ + ImGuiSettingsWindow* settings = FindWindowSettings(name); + if (!settings) + settings = AddWindowSettings(name); + return (void*)settings; +} + +static void SettingsHandlerWindow_ReadLine(ImGuiContext&, void* entry, const char* line) +{ + ImGuiSettingsWindow* settings = (ImGuiSettingsWindow*)entry; + float x, y; + int i; + if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y); + else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize); + else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0); +} + +static void SettingsHandlerWindow_WriteAll(ImGuiContext& g, ImGuiTextBuffer* buf) +{ + // Gather data from windows that were active during this session + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + continue; + ImGuiSettingsWindow* settings = FindWindowSettings(window->Name); + if (!settings) // This will only return NULL in the rare instance where the window was first created with ImGuiWindowFlags_NoSavedSettings then had the flag disabled later on. We don't bind settings in this case (bug #1000). + continue; + settings->Pos = window->Pos; + settings->Size = window->SizeFull; + settings->Collapsed = window->Collapsed; + } + + // Write a buffer + // If a window wasn't opened in this session we preserve its settings + buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve + for (int i = 0; i != g.SettingsWindows.Size; i++) + { + const ImGuiSettingsWindow* settings = &g.SettingsWindows[i]; + if (settings->Pos.x == FLT_MAX) + continue; + const char* name = settings->Name; + if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + name = p; + buf->appendf("[Window][%s]\n", name); + buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); + buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); + buf->appendf("Collapsed=%d\n", settings->Collapsed); + buf->appendf("\n"); + } +} + void ImGui::Initialize() { ImGuiContext& g = *GImGui; g.LogClipboard = (ImGuiTextBuffer*)ImGui::MemAlloc(sizeof(ImGuiTextBuffer)); IM_PLACEMENT_NEW(g.LogClipboard) ImGuiTextBuffer(); + // Add .ini handle for ImGuiWindow type + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHash("Window", 0, 0); + ini_handler.ReadOpenEntryFn = SettingsHandlerWindow_ReadOpenEntry; + ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; + ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; + g.SettingsHandlers.push_back(ini_handler); + + // Load .ini file IM_ASSERT(g.SettingsWindows.empty()); LoadIniSettingsFromDisk(g.IO.IniFilename); g.Initialized = true; @@ -2506,7 +2577,6 @@ void ImGui::Shutdown() g.MovingWindow = NULL; for (int i = 0; i < g.SettingsWindows.Size; i++) ImGui::MemFree(g.SettingsWindows[i].Name); - g.SettingsWindows.clear(); g.ColorModifiers.clear(); g.StyleModifiers.clear(); g.FontStack.clear(); @@ -2522,6 +2592,9 @@ void ImGui::Shutdown() g.InputTextState.InitialText.clear(); g.InputTextState.TempTextBuffer.clear(); + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + if (g.LogFile && g.LogFile != stdout) { fclose(g.LogFile); @@ -2562,54 +2635,64 @@ static ImGuiSettingsWindow* AddWindowSettings(const char* name) return settings; } -// Zero-tolerance, poor-man .ini parsing -// FIXME: Write something less rubbish static void LoadIniSettingsFromDisk(const char* ini_filename) { if (!ini_filename) return; - int file_size; - char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_size, 1); + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", NULL, +1); if (!file_data) return; - LoadIniSettingsFromMemory(file_data, file_data + file_size); + LoadIniSettingsFromMemory(file_data); ImGui::MemFree(file_data); } -static void LoadIniSettingsFromMemory(const char* buf, const char* buf_end) +// Zero-tolerance, no error reporting, cheap .ini parsing +static void LoadIniSettingsFromMemory(const char* buf_readonly) { + // For convenience and to make the code simpler, we'll write zero terminators inside the buffer. So let's create a writable copy. + char* buf = ImStrdup(buf_readonly); + char* buf_end = buf + strlen(buf); + ImGuiContext& g = *GImGui; - if (!buf_end) - buf_end = buf + strlen(buf); - ImGuiSettingsWindow* settings = NULL; - for (const char* line_start = buf; line_start < buf_end; ) + void* entry_data = NULL; + const ImGuiSettingsHandler* entry_handler = NULL; + + char* line_end = NULL; + for (char* line = buf; line < buf_end; line = line_end + 1) { - const char* line_end = line_start; + // Skip new lines markers, then find end of the line + while (*line == '\n' || *line == '\r') + line++; + line_end = line; while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') line_end++; + line_end[0] = 0; - if (line_start[0] == '[' && line_end > line_start && line_end[-1] == ']') + if (line[0] == '[' && line_end > line && line_end[-1] == ']') { - char name[64]; - ImFormatString(name, IM_ARRAYSIZE(name), "%.*s", (int)(line_end-line_start-2), line_start+1); - settings = FindWindowSettings(name); - if (!settings) - settings = AddWindowSettings(name); + // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. + char* name_end = line_end - 1; + *name_end = 0; + char* type_start = line + 1; + char* type_end = ImStrchrRange(type_start, name_end, ']'); + char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + if (type_start && type_end && name_start++ && name_end) + { + const ImGuiID type_hash = ImHash(type_start, type_end - type_start, 0); + entry_handler = NULL; + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size && entry_handler == NULL; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + entry_handler = &g.SettingsHandlers[handler_n]; + entry_data = entry_handler ? entry_handler->ReadOpenEntryFn(g, name_start) : NULL; + } } - else if (settings) + else if (entry_handler != NULL && entry_data != NULL) { - float x, y; - int i; - if (sscanf(line_start, "Pos=%f,%f", &x, &y) == 2) - settings->Pos = ImVec2(x, y); - else if (sscanf(line_start, "Size=%f,%f", &x, &y) == 2) - settings->Size = ImMax(ImVec2(x, y), g.Style.WindowMinSize); - else if (sscanf(line_start, "Collapsed=%d", &i) == 1) - settings->Collapsed = (i != 0); + // Let type handler parse the line + entry_handler->ReadLineFn(g, entry_data, line); } - - line_start = line_end+1; } + ImGui::MemFree(buf); } static void SaveIniSettingsToDisk(const char* ini_filename) @@ -2622,7 +2705,6 @@ static void SaveIniSettingsToDisk(const char* ini_filename) ImVector buf; SaveIniSettingsToMemory(buf); - // Write .ini file FILE* f = ImFileOpen(ini_filename, "wt"); if (!f) return; @@ -2635,39 +2717,11 @@ static void SaveIniSettingsToMemory(ImVector& out_buf) ImGuiContext& g = *GImGui; g.SettingsDirtyTimer = 0.0f; - // Gather data from windows that were active during this session - for (int i = 0; i != g.Windows.Size; i++) - { - ImGuiWindow* window = g.Windows[i]; - if (window->Flags & ImGuiWindowFlags_NoSavedSettings) - continue; - ImGuiSettingsWindow* settings = FindWindowSettings(window->Name); - if (!settings) // This will only return NULL in the rare instance where the window was first created with ImGuiWindowFlags_NoSavedSettings then had the flag disabled later on. We don't bind settings in this case (bug #1000). - continue; - settings->Pos = window->Pos; - settings->Size = window->SizeFull; - settings->Collapsed = window->Collapsed; - } - - // Write a buffer - // If a window wasn't opened in this session we preserve its settings ImGuiTextBuffer buf; - buf.reserve(g.SettingsWindows.Size * 64); // ballpark reserve - for (int i = 0; i != g.SettingsWindows.Size; i++) - { - const ImGuiSettingsWindow* settings = &g.SettingsWindows[i]; - if (settings->Pos.x == FLT_MAX) - continue; - const char* name = settings->Name; - if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() - name = p; - buf.appendf("[%s]\n", name); - buf.appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y); - buf.appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y); - buf.appendf("Collapsed=%d\n", settings->Collapsed); - buf.appendf("\n"); - } + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + g.SettingsHandlers[handler_n].WriteAllFn(g, &buf); + buf.Buf.pop_back(); // Remove extra zero-terminator used by ImGuiTextBuffer out_buf.swap(buf.Buf); } diff --git a/imgui_internal.h b/imgui_internal.h index ed227929..e5ecb8b0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -106,6 +106,7 @@ IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, int count); IMGUI_API void ImStrncpy(char* dst, const char* src, int count); IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrchrRange(const char* str_begin, const char* str_end, char c); IMGUI_API int ImStrlenW(const ImWchar* str); IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); @@ -379,6 +380,15 @@ struct ImGuiSettingsWindow bool Collapsed; }; +struct ImGuiSettingsHandler +{ + const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' + ImGuiID TypeHash; // == ImHash(TypeName, 0, 0) + void* (*ReadOpenEntryFn)(ImGuiContext& ctx, const char* name); + void (*ReadLineFn)(ImGuiContext& ctx, void* entry, const char* line); + void (*WriteAllFn)(ImGuiContext& ctx, ImGuiTextBuffer* out_buf); +}; + // Mouse cursor data (used when io.MouseDrawCursor is set) struct ImGuiMouseCursorData { @@ -438,8 +448,6 @@ struct ImGuiContext ImGuiWindow* ActiveIdWindow; ImGuiWindow* MovingWindow; // Track the child window we clicked on to move a window. ImGuiID MovingWindowMoveId; // == MovingWindow->MoveId - ImVector SettingsWindows; // .ini Settings - 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() @@ -488,6 +496,11 @@ struct ImGuiContext ImVector PrivateClipboard; // If no custom clipboard handler is defined ImVec2 OsImePosRequest, OsImePosSet; // Cursor position request & last passed to the OS Input Method Editor + // Settings + float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero + ImVector SettingsWindows; // .ini settings for ImGuiWindow + ImVector SettingsHandlers; // List of .ini settings handlers + // Logging bool LogEnabled; FILE* LogFile; // If != NULL log to stdout/ file @@ -532,7 +545,6 @@ struct ImGuiContext ActiveIdWindow = NULL; MovingWindow = NULL; MovingWindowMoveId = 0; - SettingsDirtyTimer = 0.0f; SetNextWindowPosVal = ImVec2(0.0f, 0.0f); SetNextWindowSizeVal = ImVec2(0.0f, 0.0f); @@ -565,6 +577,8 @@ struct ImGuiContext MouseCursor = ImGuiMouseCursor_Arrow; memset(MouseCursorData, 0, sizeof(MouseCursorData)); + SettingsDirtyTimer = 0.0f; + LogEnabled = false; LogFile = NULL; LogClipboard = NULL; From e000ee01169f735b0ddc91553b42ff3a857e9b9b Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 10:48:01 +0100 Subject: [PATCH 24/30] Examples: DirectX9: Handle loss of D3D9 device (D3DERR_DEVICELOST). (#1464) --- examples/directx9_example/main.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 5a5c0d19..30c820ef 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -154,7 +154,15 @@ int main(int, char**) ImGui::Render(); g_pd3dDevice->EndScene(); } - g_pd3dDevice->Present(NULL, NULL, NULL, NULL); + HRESULT result = g_pd3dDevice->Present(NULL, NULL, NULL, NULL); + + // Handle loss of D3D9 device + if (result == D3DERR_DEVICELOST && g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) + { + ImGui_ImplDX9_InvalidateDeviceObjects(); + g_pd3dDevice->Reset(&g_d3dpp); + ImGui_ImplDX9_CreateDeviceObjects(); + } } ImGui_ImplDX9_Shutdown(); From f3ec608c19462e4829ca2bf5833511290ea770b0 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 00:32:25 +0100 Subject: [PATCH 25/30] Settings: Initializing ImGuiSettingsWindow so external users don't end up with uncleared data. Exposed MarkIniSettingsDirty() in imgui_internal.h --- imgui.cpp | 7 +++++++ imgui_internal.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 41b3b621..72dda932 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2725,6 +2725,13 @@ static void SaveIniSettingsToMemory(ImVector& out_buf) out_buf.swap(buf.Buf); } +void ImGui::MarkIniSettingsDirty() +{ + ImGuiContext& g = *GImGui; + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + static void MarkIniSettingsDirty(ImGuiWindow* window) { ImGuiContext& g = *GImGui; diff --git a/imgui_internal.h b/imgui_internal.h index e5ecb8b0..249dff85 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -378,6 +378,8 @@ struct ImGuiSettingsWindow ImVec2 Pos; ImVec2 Size; bool Collapsed; + + ImGuiSettingsWindow() { Name = NULL; Id = 0; Pos = Size = ImVec2(0,0); Collapsed = false; } }; struct ImGuiSettingsHandler @@ -801,6 +803,8 @@ namespace ImGui IMGUI_API void Initialize(); + IMGUI_API void MarkIniSettingsDirty(); + IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); IMGUI_API void ClearActiveID(); IMGUI_API void SetHoveredID(ImGuiID id); From 4c4f1b0224adcfbd35e6d83577ba12f95067f5ab Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 00:33:03 +0100 Subject: [PATCH 26/30] ImVector: Added ImVector::push_front helper. --- imgui.h | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.h b/imgui.h index 309730f2..f0920910 100644 --- a/imgui.h +++ b/imgui.h @@ -983,6 +983,7 @@ public: inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size+1)); Data[Size++] = v; } inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); } inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; } From e5ebe42207225d5f6e2165f90bbae79b283994c0 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 00:33:12 +0100 Subject: [PATCH 27/30] Settings: Make ImGuiWindow settings always first in the list. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 72dda932..0ecbedb6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2537,7 +2537,7 @@ void ImGui::Initialize() ini_handler.ReadOpenEntryFn = SettingsHandlerWindow_ReadOpenEntry; ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; - g.SettingsHandlers.push_back(ini_handler); + g.SettingsHandlers.push_front(ini_handler); // Load .ini file IM_ASSERT(g.SettingsWindows.empty()); From c8b5b569dacd25abc45cda1bf70bff53b15ac945 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 11:26:14 +0100 Subject: [PATCH 28/30] Examples: DirectX9: Call EndFrame(), fix for assert added in 9a44d447cd29096c74e38bec917015c0ee1ffaea --- examples/directx9_example/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 30c820ef..af53ddb3 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -144,6 +144,7 @@ int main(int, char**) } // Rendering + ImGui::EndFrame(); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false); From 1a8a7c9d170a49e9c3170df59674eab74810bab6 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 16:23:46 +0100 Subject: [PATCH 29/30] Settings: Import old style .ini file --- imgui.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0ecbedb6..60b1d1c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2676,15 +2676,22 @@ static void LoadIniSettingsFromMemory(const char* buf_readonly) char* type_start = line + 1; char* type_end = ImStrchrRange(type_start, name_end, ']'); char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; - if (type_start && type_end && name_start++ && name_end) + if (!type_end || !name_start) { - const ImGuiID type_hash = ImHash(type_start, type_end - type_start, 0); - entry_handler = NULL; - for (int handler_n = 0; handler_n < g.SettingsHandlers.Size && entry_handler == NULL; handler_n++) - if (g.SettingsHandlers[handler_n].TypeHash == type_hash) - entry_handler = &g.SettingsHandlers[handler_n]; - entry_data = entry_handler ? entry_handler->ReadOpenEntryFn(g, name_start) : NULL; + name_start = type_start; // Import legacy entries that have no type + type_start = "Window"; } + else + { + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' + } + const ImGuiID type_hash = ImHash(type_start, 0, 0); + entry_handler = NULL; + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size && entry_handler == NULL; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + entry_handler = &g.SettingsHandlers[handler_n]; + entry_data = entry_handler ? entry_handler->ReadOpenEntryFn(g, name_start) : NULL; } else if (entry_handler != NULL && entry_data != NULL) { From 4a43632163b49744455e04ca9654e045708dccab Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 28 Nov 2017 17:27:54 +0100 Subject: [PATCH 30/30] Build fix --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 60b1d1c5..91de2d97 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2671,11 +2671,11 @@ static void LoadIniSettingsFromMemory(const char* buf_readonly) if (line[0] == '[' && line_end > line && line_end[-1] == ']') { // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. - char* name_end = line_end - 1; - *name_end = 0; - char* type_start = line + 1; + line_end[-1] = 0; + const char* name_end = line_end - 1; + const char* type_start = line + 1; char* type_end = ImStrchrRange(type_start, name_end, ']'); - char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; if (!type_end || !name_start) { name_start = type_start; // Import legacy entries that have no type