diff --git a/README.md b/README.md index dc4a21207..ac5ac1693 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ The bulk of example user code is contained within the ImGui::ShowTestWindow() fu How do you use ImGui on a platform that may not have a mouse or keyboard? -I recommend using [Synergy](http://synergy-project.org). With the uSynergy.c micro client running on your platform and connecting to your PC, you can seamlessly use your PC input devices from a video game console or a tablet. ImGui allows to increase the hit box of widgets (via the _TouchPadding_ setting) to accomodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse to allow optimising for screen real-estate. +I recommend using [Synergy](http://synergy-project.org) ([sources](https://github.com/synergy/synergy)). With the uSynergy.c micro client running on your platform and connecting to your PC, you can seamlessly use your PC input devices from a video game console or a tablet. ImGui allows to increase the hit box of widgets (via the _TouchPadding_ setting) to accomodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse to allow optimising for screen real-estate. I integrated ImGui in my engine and the text or lines are blurry.. diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index b051fd248..0064a93a1 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -188,7 +188,8 @@ int main(int, char**) // 2. Show another simple window, this time using an explicit Begin/End pair if (show_another_window) { - ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); + ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Another Window", &show_another_window); ImGui::Text("Hello"); ImGui::End(); } diff --git a/examples/directx9_example/main.cpp b/examples/directx9_example/main.cpp index 9a01ba31e..ce8ca4774 100644 --- a/examples/directx9_example/main.cpp +++ b/examples/directx9_example/main.cpp @@ -115,7 +115,8 @@ int main(int, char**) // 2. Show another simple window, this time using an explicit Begin/End pair if (show_another_window) { - ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); + ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Another Window", &show_another_window); ImGui::Text("Hello"); ImGui::End(); } diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 07bf5a579..cd43effc2 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -329,11 +329,18 @@ void ImGui_ImplGlfwGL3_NewFrame() // Setup inputs // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) - double mouse_x, mouse_y; - glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); - mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels - mouse_y *= (float)display_h / h; - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels + mouse_y *= (float)display_h / h; + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + } + else + { + io.MousePos = ImVec2(-1,-1); + } for (int i = 0; i < 3; i++) { diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.h b/examples/opengl3_example/imgui_impl_glfw_gl3.h index 7b1815771..81b59528d 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.h +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.h @@ -16,5 +16,5 @@ bool ImGui_ImplGlfwGL3_CreateDeviceObjects(); // You can also handle inputs yourself and use those as a reference. void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); -void ImGui_ImplGlFwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c); diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index dc88a7c66..9f0207aaa 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -59,7 +59,8 @@ int main(int, char**) // 2. Show another simple window, this time using an explicit Begin/End pair if (show_another_window) { - ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); + ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Another Window", &show_another_window); ImGui::Text("Hello"); ImGui::End(); } diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 00313e453..b7a4844cb 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -233,11 +233,18 @@ void ImGui_ImplGlfw_NewFrame() // Setup inputs // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) - double mouse_x, mouse_y; - glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); - mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels - mouse_y *= (float)display_h / h; - io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + mouse_x *= (float)display_w / w; // Convert mouse coordinates to pixels + mouse_y *= (float)display_h / h; + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) + } + else + { + io.MousePos = ImVec2(-1,-1); + } for (int i = 0; i < 3; i++) { diff --git a/examples/opengl_example/main.cpp b/examples/opengl_example/main.cpp index 471f9a29a..92bf842cd 100644 --- a/examples/opengl_example/main.cpp +++ b/examples/opengl_example/main.cpp @@ -53,7 +53,8 @@ int main(int, char**) // 2. Show another simple window, this time using an explicit Begin/End pair if (show_another_window) { - ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); + ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Another Window", &show_another_window); ImGui::Text("Hello"); ImGui::End(); } diff --git a/imgui.cpp b/imgui.cpp index b3b8ac90f..74a08cf3b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.36 WIP +// ImGui library v1.37 WIP // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui @@ -34,7 +34,7 @@ Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: - doesn't look fancy, doesn't animate - limited layout features, intricate layouts are typically crafted in code - - occasionally uses statically sized buffers for string manipulations - won't crash, but some long text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction. + - occasionally uses statically sized buffers for string manipulations - won't crash, but some very long pieces of text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction. END-USER GUIDE @@ -66,16 +66,17 @@ - read the FAQ below this section! - your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs. - call and read ImGui::ShowTestWindow() for sample code demonstrating most features. - - see examples/ folder for standalone sample applications. - - customization: use the style editor or PushStyleColor/PushStyleVar to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). + - see examples/ folder for standalone sample applications. e.g. examples/opengl_example/ + - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme). - getting started: - - initialisation: call ImGui::GetIO() and fill the 'Settings' data. + - initialisation: call ImGui::GetIO() to retrieve the ImGuiIO structure and fill the 'Settings' data. - every frame: 1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the 'Input' data, then call ImGui::NewFrame(). 2/ use any ImGui function you want between NewFrame() and Render() 3/ ImGui::Render() to render all the accumulated command-lists. it will call your RenderDrawListFn handler that you set in the IO structure. - - all rendering information are stored into command-lists until ImGui::Render() is called. + - all rendering information are stored into command-lists until ImGui::Render() is called. + - ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you must provide. - effectively it means you can create widgets at any time in your code, regardless of "update" vs "render" considerations. - refer to the examples applications in the examples/ folder for instruction on how to setup your code. - a typical application skeleton may be: @@ -129,10 +130,11 @@ Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. 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. + - 2015/03/17 (1.36) - renamed GetItemRectMin()/GetItemRectMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete). - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing - - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function. + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete). - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth - - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function. + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function (will obsolete). - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior @@ -177,7 +179,7 @@ - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) - A primer on the meaning and use of ID in ImGui: + A primer on the meaning and use of IDs in ImGui: - widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget). to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer. @@ -185,6 +187,8 @@ Button("OK"); // Label = "OK", ID = hash of "OK" Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" + - element that are not interactive, such as Text() items don't need an ID. + - ID are uniquely scoped within Windows so no conflict can happen if you have two buttons called "OK" in two different Windows. - when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases. @@ -202,16 +206,16 @@ Button("Click"); // Label = "Click", ID = hash of "Click" PushID("node"); - Button("Click"); // Label = "Click", ID = hash of "node" and "Click" + Button("Click"); // Label = "Click", ID = hash of "node" + "Click" for (int i = 0; i < 100; i++) { PushID(i); - Button("Click"); // Label = "Click", ID = hash of "node" and i and "label" + Button("Click"); // Label = "Click", ID = hash of "node" + i + "label" PopID(); } PopID(); PushID(my_ptr); - Button("Click"); // Label = "Click", ID = hash of ptr and "Click" + Button("Click"); // Label = "Click", ID = hash of ptr + "Click" PopID(); so if you have a loop creating multiple items, you can use PushID() / PopID() with the index of each item, or their pointer, etc. @@ -233,6 +237,8 @@ ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() + // the first loaded font gets used by default + // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime If you want to display Chinese, Japanese, Korean characters, pass custom Unicode ranges when loading a font: @@ -250,27 +256,24 @@ ISSUES & TODO-LIST ================== - - misc: merge or clarify ImVec4 / ImGuiAabb, they are essentially duplicate containers + - misc: merge or clarify ImVec4 vs ImRect? - window: add horizontal scroll - window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit? - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. - window: allow resizing of child windows (possibly given min/max for each axis?) - window: background options for child windows, border option (disable rounding) - window: resizing from any sides? + mouse cursor directives for app. - - widgets: clicking on widget b while widget a should activate widget b (doesn't anymore because of hover capture) - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. - - widgets: clip text? hover clipped text shows it in a tooltip or in-place overlay + - widgets: clean up widgets internal toward exposing everything. - main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them. - - main: IsItemHovered() returns true even if mouse is active on another widget (e.g. dragging outside of sliders). Maybe not a sensible default? Add parameter or alternate function? - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode? -!- input number: very large int not reliably supported because of int<>float conversions. +!- input number: large int not reliably supported because of int<>float conversions. - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: use mouse wheel to step up/down - input number: non-decimal input. - - text: vertical alignment (e.g. for Text after a large widget) - - text: proper horizontal centering + - text: proper alignment options - layout: horizontal layout helper (github issue #97) - layout: more generic alignment state (left/right/centered) for single items? - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding. @@ -292,7 +295,8 @@ - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID) - file selection widget -> build the tool in our codebase to improve model-dialog idioms - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - - slider: initial absolute click is imprecise. change to relative movement slider? hide mouse cursor, allow more precise input using less screen-space. same as scrollbar. + - slider: initial absolute click is imprecise. change to relative movement slider (same as scrollbar). + - slider: add dragging-based widgets to edit values with mouse (on 2 axises), saving screen real-estate. - text edit: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now. - text edit: centered text for slider as input text so it matches typical positioning. - text edit: flag to disable live update of the user buffer. @@ -300,14 +304,15 @@ - text edit: add multi-line text edit - tree: add treenode/treepush int variants? because (void*) cast from int warns on some platforms/settings - settings: write more decent code to allow saving/loading new fields - - settings: api for per-tool simple persistent data (bool,int,float) in .ini file + - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file ! style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost. - style: checkbox: padding for "active" color should be a multiplier of the - style: colorbox not always square? - text: simple markup language for color change? - log: LogButtons() options for specifying depth and/or hiding depth slider - log: have more control over the log scope (e.g. stop logging when leaving current tree node scope) - - log: be able to right-click and log a window or tree-node into tty/file/clipboard / generalized context menu? + - log: be able to log anything (e.g. right-click on a window/tree-node, shows context menu? log into tty/file/clipboard) + - log: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?). code is commented because it fails with multiple Begin/End pairs. - filters: set a current filter that tree node can automatically query to hide themselves - filters: handle wildcards (with implicit leading/trailing *), regexps - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) @@ -317,17 +322,15 @@ - input: support track pad style scrolling & slider edit. - tooltip: move to fit within screen (e.g. when mouse cursor is right of the screen). - portability: big-endian test/support (github issue #81) - - misc: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?) - misc: mark printf compiler attributes on relevant functions - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL) - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon? - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? - style editor: color child window height expressed in multiple of line height. - - optimization/render: use indexed rendering to reduce vertex data cost (for remote/networked imgui) + - optimization/render: use indexed rendering to reduce vertex data cost (e.g. for remote/networked imgui) - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimization: turn some the various stack vectors into statically-sized arrays - optimization: better clipping for multi-component widgets - - optimization: specialize for height based clipping first (assume widgets never go up + height tests before width tests?) */ #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) @@ -413,16 +416,16 @@ using namespace IMGUI_STB_NAMESPACE; // Forward Declarations //------------------------------------------------------------------------- +struct ImRect; struct ImGuiColMod; struct ImGuiStyleMod; -struct ImGuiAabb; struct ImGuiDrawContext; struct ImGuiTextEditState; struct ImGuiIniData; struct ImGuiState; struct ImGuiWindow; -static bool ButtonBehavior(const ImGuiAabb& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false); +static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false); static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); @@ -432,13 +435,13 @@ static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool static void RenderCollapseTriangle(ImVec2 p_min, bool opened, float scale = 1.0f, bool shadow = false); static void SetFont(ImFont* font); -static bool ItemAdd(const ImGuiAabb& bb, const ImGuiID* id); -static void ItemSize(ImVec2 size, ImVec2* adjust_start_offset = NULL); -static void ItemSize(const ImGuiAabb& bb, ImVec2* adjust_start_offset = NULL); +static bool ItemAdd(const ImRect& bb, const ImGuiID* id); +static void ItemSize(ImVec2 size, float text_offset_y = 0.0f); +static void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); static void PushColumnClipRect(int column_index = -1); -static bool IsClipped(const ImGuiAabb& bb); +static bool IsClipped(const ImRect& bb); -static bool IsMouseHoveringBox(const ImGuiAabb& bb); +static bool IsMouseHoveringRect(const ImRect& bb); static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true); static void Scrollbar(ImGuiWindow* window); @@ -503,18 +506,19 @@ ImGuiStyle::ImGuiStyle() FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) - TouchExtraPadding = ImVec2(0,0); // Expand bounding box for touch-based system where touch position is not accurate enough (unnecessary for mouse inputs). Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget running. So dont grow this too much! + TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! AutoFitPadding = ImVec2(8,8); // Extra space after auto-fit (double-clicking on resize grip) WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin() IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollbarWidth = 16.0f; // Width of the vertical scrollbar GrabMinSize = 10.0f; // Minimum width/height of a slider or scrollbar grab + DisplaySafeAreaPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - Colors[ImGuiCol_Border] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f); Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); @@ -535,9 +539,9 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); Colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); Colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); - Colors[ImGuiCol_Column] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - Colors[ImGuiCol_ColumnHovered] = ImVec4(0.60f, 0.40f, 0.40f, 1.00f); - Colors[ImGuiCol_ColumnActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f); + Colors[ImGuiCol_Column] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + Colors[ImGuiCol_ColumnHovered] = ImVec4(0.70f, 0.60f, 0.60f, 1.00f); + Colors[ImGuiCol_ColumnActive] = ImVec4(0.90f, 0.70f, 0.70f, 1.00f); Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f); @@ -823,7 +827,6 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes) { IM_ASSERT(filename && file_open_mode && out_file_data && out_file_size); - IM_ASSERT(padding_bytes >= 0); *out_file_data = NULL; *out_file_size = 0; @@ -875,31 +878,53 @@ struct ImGuiStyleMod // Style modifier, backup of modified data so we can res ImVec2 PreviousValue; }; -struct ImGuiAabb // 2D axis aligned bounding-box +struct ImRect // 2D axis aligned bounding-box { ImVec2 Min; ImVec2 Max; - ImGuiAabb() { Min = ImVec2(FLT_MAX,FLT_MAX); Max = ImVec2(-FLT_MAX,-FLT_MAX); } - ImGuiAabb(const ImVec2& min, const ImVec2& max) { Min = min; Max = max; } - ImGuiAabb(const ImVec4& v) { Min.x = v.x; Min.y = v.y; Max.x = v.z; Max.y = v.w; } - ImGuiAabb(float x1, float y1, float x2, float y2) { Min.x = x1; Min.y = y1; Max.x = x2; Max.y = y2; } + ImRect() { Min = ImVec2(FLT_MAX,FLT_MAX); Max = ImVec2(-FLT_MAX,-FLT_MAX); } + ImRect(const ImVec2& min, const ImVec2& max) { Min = min; Max = max; } + ImRect(const ImVec4& v) { Min.x = v.x; Min.y = v.y; Max.x = v.z; Max.y = v.w; } + ImRect(float x1, float y1, float x2, float y2) { Min.x = x1; Min.y = y1; Max.x = x2; Max.y = y2; } - ImVec2 GetCenter() const { return Min + (Max-Min)*0.5f; } - ImVec2 GetSize() const { return Max-Min; } - float GetWidth() const { return (Max-Min).x; } - float GetHeight() const { return (Max-Min).y; } - ImVec2 GetTL() const { return Min; } - ImVec2 GetTR() const { return ImVec2(Max.x,Min.y); } - ImVec2 GetBL() const { return ImVec2(Min.x,Max.y); } - ImVec2 GetBR() const { return Max; } - bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x <= Max.x && p.y <= Max.y; } - bool Contains(const ImGuiAabb& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } - bool Overlaps(const ImGuiAabb& r) const { return r.Min.y <= Max.y && r.Max.y >= Min.y && r.Min.x <= Max.x && r.Max.x >= Min.x; } - void Add(const ImVec2& rhs) { Min.x = ImMin(Min.x, rhs.x); Min.y = ImMin(Min.y, rhs.y); Max.x = ImMax(Max.x, rhs.x); Max.y = ImMax(Max.x, rhs.x); } - void Add(const ImGuiAabb& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); } - void Expand(const ImVec2& sz) { Min -= sz; Max += sz; } - void Clip(const ImGuiAabb& clip) { Min.x = ImMax(Min.x, clip.Min.x); Min.y = ImMax(Min.y, clip.Min.y); Max.x = ImMin(Max.x, clip.Max.x); Max.y = ImMin(Max.y, clip.Max.y); } + ImVec2 GetCenter() const { return Min + (Max-Min)*0.5f; } + ImVec2 GetSize() const { return Max-Min; } + float GetWidth() const { return (Max-Min).x; } + float GetHeight() const { return (Max-Min).y; } + ImVec2 GetTL() const { return Min; } + ImVec2 GetTR() const { return ImVec2(Max.x,Min.y); } + ImVec2 GetBL() const { return ImVec2(Min.x,Max.y); } + ImVec2 GetBR() const { return Max; } + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x <= Max.x && p.y <= Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y <= Max.y && r.Max.y >= Min.y && r.Min.x <= Max.x && r.Max.x >= Min.x; } + void Add(const ImVec2& rhs) { Min.x = ImMin(Min.x, rhs.x); Min.y = ImMin(Min.y, rhs.y); Max.x = ImMax(Max.x, rhs.x); Max.y = ImMax(Max.x, rhs.x); } + void Add(const ImRect& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min -= amount; Max += amount; } + void Clip(const ImRect& clip) { Min.x = ImMax(Min.x, clip.Min.x); Min.y = ImMax(Min.y, clip.Min.y); Max.x = ImMin(Max.x, clip.Max.x); Max.y = ImMin(Max.y, clip.Max.y); } + ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const + { + if (!on_edge && Contains(p)) + return p; + if (p.x > Max.x) p.x = Max.x; + else if (p.x < Min.x) p.x = Min.x; + if (p.y > Max.y) p.y = Max.y; + else if (p.y < Min.y) p.y = Min.y; + return p; + } +}; +typedef ImRect ImGuiAabb; // FIXME-OBSOLETE + +struct ImGuiGroupData +{ + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + float BackupColumnsStartX; + float BackupCurrentLineHeight; + float BackupCurrentLineTextBaseOffset; + float BackupLogLinePosY; }; // Temporary per-window data, reset at the beginning of the frame @@ -908,21 +933,26 @@ struct ImGuiDrawContext ImVec2 CursorPos; ImVec2 CursorPosPrevLine; ImVec2 CursorStartPos; + ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame float CurrentLineHeight; + float CurrentLineTextBaseOffset; float PrevLineHeight; - float LogLineHeight; + float PrevLineTextBaseOffset; + float LogLinePosY; int TreeDepth; ImGuiID LastItemID; - ImGuiAabb LastItemAabb; - bool LastItemHovered; + ImRect LastItemRect; + bool LastItemHoveredAndUsable; + bool LastItemHoveredRectOnly; ImVector ChildWindows; ImVector AllowKeyboardFocus; ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window ImVector TextWrapPos; + ImVector GroupStack; ImGuiColorEditMode ColorEditMode; ImGuiStorage* StateStorage; - float ColumnsStartX; // Start position from left of window (increased by TreePush/TreePop, etc.) + float ColumnsStartX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. int ColumnsCurrent; int ColumnsCount; @@ -935,13 +965,14 @@ struct ImGuiDrawContext ImGuiDrawContext() { - CursorPos = CursorPosPrevLine = CursorStartPos = ImVec2(0.0f, 0.0f); + CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); CurrentLineHeight = PrevLineHeight = 0.0f; - LogLineHeight = -1.0f; + CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; + LogLinePosY = -1.0f; TreeDepth = 0; LastItemID = 0; - LastItemAabb = ImGuiAabb(0.0f,0.0f,0.0f,0.0f); - LastItemHovered = false; + LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f); + LastItemHoveredAndUsable = LastItemHoveredRectOnly = false; StateStorage = NULL; ColumnsStartX = 0.0f; @@ -1132,12 +1163,11 @@ struct ImGuiWindow ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame - ImVec2 SizeContentsCurrent; // Size of contents, currently extending + ImGuiID MoveID; // == window->GetID("#MOVE") float ScrollY; float NextScrollY; bool ScrollbarY; bool Visible; // Set to true on Begin() - bool Accessed; // Set to true when any widget access the current window bool Collapsed; // Set when collapsing window to become only title-bar bool SkipItems; // == Visible && !Collapsed int AutoFitFrames; @@ -1149,7 +1179,7 @@ struct ImGuiWindow ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack ImVector ClipRectStack; // Scissoring / clipping rectangle. x1, y1, x2, y2. - ImGuiAabb ClippedAabb; // = ClipRectStack.front() after setup in Begin() + ImRect ClippedRect; // = ClipRectStack.front() after setup in Begin() int LastFrameDrawn; float ItemWidthDefault; ImGuiStorage StateStorage; @@ -1176,12 +1206,12 @@ public: bool FocusItemRegister(bool is_active, bool tab_stop = true); // Return true if focus is requested void FocusItemUnregister(); - ImGuiAabb Aabb() const { return ImGuiAabb(Pos, Pos+Size); } + ImRect Rect() const { return ImRect(Pos, Pos+Size); } ImFont* Font() const { return GImGui->Font; } float FontSize() const { return GImGui->FontSize * FontWindowScale; } ImVec2 CursorPos() const { return DC.CursorPos; } float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : FontSize() + GImGui->Style.FramePadding.y * 2.0f; } - ImGuiAabb TitleBarAabb() const { return ImGuiAabb(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } + ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders)) ? ImVec2(0,0) : GImGui->Style.WindowPadding; } ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); } ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } @@ -1191,7 +1221,6 @@ static inline ImGuiWindow* GetCurrentWindow() { ImGuiState& g = *GImGui; IM_ASSERT(g.CurrentWindow != NULL); // ImGui::NewFrame() hasn't been called yet? - g.CurrentWindow->Accessed = true; return g.CurrentWindow; } @@ -1470,16 +1499,16 @@ ImGuiWindow::ImGuiWindow(const char* name) Name = ImStrdup(name); ID = ImHash(name, 0); IDStack.push_back(ID); + MoveID = GetID("#MOVE"); Flags = 0; PosFloat = Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); - SizeContents = SizeContentsCurrent = ImVec2(0.0f, 0.0f); + SizeContents = ImVec2(0.0f, 0.0f); ScrollY = 0.0f; NextScrollY = 0.0f; ScrollbarY = false; Visible = false; - Accessed = false; Collapsed = false; SkipItems = false; AutoFitFrames = -1; @@ -1904,7 +1933,6 @@ void ImGui::NewFrame() { ImGuiWindow* window = g.Windows[i]; window->Visible = false; - window->Accessed = false; } // No window should be open at the beginning of the frame. @@ -2031,8 +2059,9 @@ void ImGui::Render() { // Hide implicit window if it hasn't been used IM_ASSERT(g.CurrentWindowStack.size() == 1); // Mismatched Begin/End - if (g.CurrentWindow && !g.CurrentWindow->Accessed) - g.CurrentWindow->Visible = false; + if (ImGuiWindow* window = g.CurrentWindow) + if (ImLengthSqr(window->DC.CursorMaxPos - window->DC.CursorStartPos) < 0.001f) + g.CurrentWindow->Visible = false; ImGui::End(); // Select window for move/focus when we're done with all our widgets (we use the root window ID here) @@ -2040,7 +2069,7 @@ void ImGui::Render() { IM_ASSERT(g.MovedWindow == NULL); g.MovedWindow = g.HoveredWindow; - SetActiveId(g.HoveredRootWindow->GetID("#MOVE")); + SetActiveId(g.HoveredRootWindow->MoveID); } // Sort the window list so that all child windows are after their parent @@ -2154,8 +2183,8 @@ static void LogText(const ImVec2& ref_pos, const char* text, const char* text_en if (!text_end) text_end = FindTextDisplayEnd(text, text_end); - const bool log_new_line = ref_pos.y > window->DC.LogLineHeight+1; - window->DC.LogLineHeight = ref_pos.y; + const bool log_new_line = ref_pos.y > window->DC.LogLinePosY+1; + window->DC.LogLinePosY = ref_pos.y; const char* text_remaining = text; if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth @@ -2404,37 +2433,37 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) continue; // Using the clipped AABB so a child window will typically be clipped by its parent. - ImGuiAabb bb(window->ClippedAabb.Min - g.Style.TouchExtraPadding, window->ClippedAabb.Max + g.Style.TouchExtraPadding); + ImRect bb(window->ClippedRect.Min - g.Style.TouchExtraPadding, window->ClippedRect.Max + g.Style.TouchExtraPadding); if (bb.Contains(pos)) return window; } return NULL; } -// Test if mouse cursor is hovering given aabb -// NB- Box is clipped by our current clip setting -// NB- Expand the aabb to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) -static bool IsMouseHoveringBox(const ImGuiAabb& bb) +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +static bool IsMouseHoveringRect(const ImRect& rect) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); // Clip - ImGuiAabb box_clipped = bb; + ImRect rect_clipped = rect; if (!window->ClipRectStack.empty()) { const ImVec4 clip_rect = window->ClipRectStack.back(); - box_clipped.Clip(ImGuiAabb(ImVec2(clip_rect.x, clip_rect.y), ImVec2(clip_rect.z, clip_rect.w))); + rect_clipped.Clip(ImRect(ImVec2(clip_rect.x, clip_rect.y), ImVec2(clip_rect.z, clip_rect.w))); } // Expand for touch input - const ImGuiAabb box_for_touch(box_clipped.Min - g.Style.TouchExtraPadding, box_clipped.Max + g.Style.TouchExtraPadding); - return box_for_touch.Contains(g.IO.MousePos); + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + return rect_for_touch.Contains(g.IO.MousePos); } -bool ImGui::IsMouseHoveringBox(const ImVec2& box_min, const ImVec2& box_max) +bool ImGui::IsMouseHoveringRect(const ImVec2& rect_min, const ImVec2& rect_max) { - return IsMouseHoveringBox(ImGuiAabb(box_min, box_max)); + return IsMouseHoveringRect(ImRect(rect_min, rect_max)); } bool ImGui::IsMouseHoveringWindow() @@ -2513,7 +2542,13 @@ ImVec2 ImGui::GetMousePos() bool ImGui::IsItemHovered() { ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemHovered; + return window->DC.LastItemHoveredAndUsable; +} + +bool ImGui::IsItemHoveredRectOnly() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.LastItemHoveredRectOnly; } bool ImGui::IsItemActive() @@ -2533,16 +2568,41 @@ bool ImGui::IsAnyItemActive() return g.ActiveId != 0; } -ImVec2 ImGui::GetItemBoxMin() +ImVec2 ImGui::GetItemActiveDragDelta() { - ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemAabb.Min; + if (ImGui::IsItemActive()) + { + ImGuiState& g = *GImGui; + if (g.IO.MouseDown[0]) + return g.IO.MousePos - g.IO.MouseClickedPos[0]; // Assume we can only get active with left-mouse button (at the moment). + } + return ImVec2(0.0f, 0.0f); } -ImVec2 ImGui::GetItemBoxMax() +ImVec2 ImGui::GetItemRectMin() { ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemAabb.Max; + return window->DC.LastItemRect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.LastItemRect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DC.LastItemRect.GetSize(); +} + +ImVec2 ImGui::CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge, float outward) +{ + ImGuiWindow* window = GetCurrentWindow(); + ImRect rect = window->DC.LastItemRect; + rect.Expand(outward); + return rect.GetClosestPoint(pos, on_edge); } // Tooltip is stored and turned into a BeginTooltip()/EndTooltip() sequence at the end of the frame. Each call override previous value. @@ -2650,7 +2710,7 @@ void ImGui::EndChild() ImGui::End(); window = GetCurrentWindow(); - ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + sz); + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + sz); ItemSize(sz); ItemAdd(bb, NULL); } @@ -2818,8 +2878,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->ClipRectStack.resize(0); // Reset contents size for auto-fitting - window->SizeContents = window->SizeContentsCurrent; - window->SizeContentsCurrent = ImVec2(0.0f, 0.0f); + window->SizeContents = window->DC.CursorMaxPos - window->Pos; + window->SizeContents.y += window->ScrollY; if (flags & ImGuiWindowFlags_ChildWindow) { @@ -2847,9 +2907,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->IDStack.resize(1); // Move window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows. - const ImGuiID move_id = window->GetID("#MOVE"); - RegisterAliveId(move_id); - if (g.ActiveId == move_id) + RegisterAliveId(window->MoveID); + if (g.ActiveId == window->MoveID) { if (g.IO.MouseDown[0]) { @@ -2878,12 +2937,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Clamp into view if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip)) { - // FIXME: Parameterize padding. - const ImVec2 pad = ImVec2(window->FontSize()*2.0f, window->FontSize()*2.0f); // FIXME: Parametrize of clarify this behavior. - if (g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + if (window->AutoFitFrames == 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. { - ImVec2 clip_min = pad; - ImVec2 clip_max = g.IO.DisplaySize - pad; + ImVec2 clip_min = style.DisplaySafeAreaPadding; + ImVec2 clip_max = g.IO.DisplaySize - style.DisplaySafeAreaPadding; window->PosFloat = ImMax(window->PosFloat + window->Size, clip_min) - window->Size; window->PosFloat = ImMin(window->PosFloat, clip_max); } @@ -2909,7 +2966,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1; window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; - ImGuiAabb title_bar_aabb = window->TitleBarAabb(); + ImRect title_bar_rect = window->TitleBarRect(); // Apply and ImClamp scrolling window->ScrollY = window->NextScrollY; @@ -2922,7 +2979,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Collapse window by double-clicking on title bar if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) { - if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringBox(title_bar_aabb) && g.IO.MouseDoubleClicked[0]) + if (!(window->Flags & ImGuiWindowFlags_NoCollapse) && g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect) && g.IO.MouseDoubleClicked[0]) { window->Collapsed = !window->Collapsed; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) @@ -2939,24 +2996,22 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg if (window->Collapsed) { // Draw title bar only - window->Size = title_bar_aabb.GetSize(); - window->DrawList->AddRectFilled(title_bar_aabb.GetTL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); + window->Size = title_bar_rect.GetSize(); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); if (window->Flags & ImGuiWindowFlags_ShowBorders) { - window->DrawList->AddRect(title_bar_aabb.GetTL()+ImVec2(1,1), title_bar_aabb.GetBR()+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); - window->DrawList->AddRect(title_bar_aabb.GetTL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_Border), window_rounding); + window->DrawList->AddRect(title_bar_rect.GetTL()+ImVec2(1,1), title_bar_rect.GetBR()+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); + window->DrawList->AddRect(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_Border), window_rounding); } } else { - window->Size = window->SizeFull; - ImU32 resize_col = 0; if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) { // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. const ImVec2 size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); - window->SizeFull = size_auto_fit; + window->Size = window->SizeFull = size_auto_fit; } else { @@ -2979,17 +3034,16 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg else if (!(window->Flags & ImGuiWindowFlags_NoResize)) { // Manual resize grip - const ImGuiAabb resize_aabb(window->Aabb().GetBR()-ImVec2(18,18), window->Aabb().GetBR()); + const ImRect resize_rect(window->Rect().GetBR()-ImVec2(18,18), window->Rect().GetBR()); const ImGuiID resize_id = window->GetID("#RESIZE"); bool hovered, held; - ButtonBehavior(resize_aabb, resize_id, &hovered, &held, true); + ButtonBehavior(resize_rect, resize_id, &hovered, &held, true); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) { // Manual auto-fit when double-clicking window->SizeFull = size_auto_fit; - window->Size = window->SizeFull; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } @@ -2997,14 +3051,14 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg { // Resize window->SizeFull = ImMax(window->SizeFull + g.IO.MouseDelta, style.WindowMinSize); - window->Size = window->SizeFull; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } } - // Update aabb immediately so that rendering right below us isn't one frame late - title_bar_aabb = window->TitleBarAabb(); + // Update rectangle immediately so that rendering right below us isn't one frame late + window->Size = window->SizeFull; + title_bar_rect = window->TitleBarRect(); } // Scrollbar @@ -3025,7 +3079,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Title bar if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_aabb.GetTL(), title_bar_aabb.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); // Borders if (window->Flags & ImGuiWindowFlags_ShowBorders) @@ -3033,7 +3087,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DrawList->AddRect(window->Pos+ImVec2(1,1), window->Pos+window->Size+ImVec2(1,1), window->Color(ImGuiCol_BorderShadow), window_rounding); window->DrawList->AddRect(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_Border), window_rounding); if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddLine(title_bar_aabb.GetBL()+ImVec2(0.5f,0.5f), title_bar_aabb.GetBR()+ImVec2(0.5f,0.5f), window->Color(ImGuiCol_Border)); + window->DrawList->AddLine(title_bar_rect.GetBL()+ImVec2(0.5f,0.5f), title_bar_rect.GetBR()+ImVec2(0.5f,0.5f), window->Color(ImGuiCol_Border)); } // Scrollbar @@ -3047,7 +3101,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg const float base_size = window->FontSize() * 1.35f; const float min_size = window_rounding + 1.0f + window->FontSize() * 0.2f; const float corner_size = ImMax(base_size, min_size); - const ImVec2 br = window->Aabb().GetBR(); + const ImVec2 br = window->Rect().GetBR(); window->DrawList->LineTo(br + ImVec2(-corner_size, 0.0f)); window->DrawList->LineTo(br + ImVec2(0.0f, -corner_size)); window->DrawList->ArcToFast(ImVec2(br.x - window_rounding, br.y - window_rounding), window_rounding, 6, 9); @@ -3061,8 +3115,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->WindowPadding().y) - ImVec2(0.0f, window->ScrollY); window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; + window->DC.CursorMaxPos = window->DC.CursorStartPos; window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f; - window->DC.LogLineHeight = window->DC.CursorPos.y - 9999.0f; + window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.ItemWidth.resize(0); window->DC.ItemWidth.push_back(window->ItemWidthDefault); @@ -3077,6 +3133,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.ColumnsStartPos.y; window->DC.TreeDepth = 0; window->DC.StateStorage = &window->StateStorage; + window->DC.GroupStack.resize(0); if (window->AutoFitFrames > 0) window->AutoFitFrames--; @@ -3095,13 +3152,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg } const ImVec2 text_size = CalcTextSize(name, NULL, true); - const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_aabb.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); + const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_rect.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); RenderTextClipped(text_min, name, NULL, &text_size, text_max); } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() - window->ClippedAabb = window->Aabb(); - window->ClippedAabb.Clip(window->ClipRectStack.front()); + window->ClippedRect = window->Rect(); + window->ClippedRect.Clip(window->ClipRectStack.front()); // Pressing CTRL+C while holding on a window copy its content to the clipboard // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. @@ -3115,16 +3172,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg // Inner clipping rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame - const ImGuiAabb title_bar_aabb = window->TitleBarAabb(); - ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Aabb().Max.y-1.5f); + const ImRect title_bar_rect = window->TitleBarRect(); + ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_rect.Max.y+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); if (window->ScrollbarY) clip_rect.z -= style.ScrollbarWidth; PushClipRect(clip_rect); - // Clear 'accessed' flag last thing - if (first_begin_of_the_frame) - window->Accessed = false; - // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). if (flags & ImGuiWindowFlags_ChildWindow) @@ -3179,9 +3232,9 @@ static void Scrollbar(ImGuiWindow* window) const ImGuiID id = window->GetID("#SCROLLY"); // Render background - ImGuiAabb bb(window->Aabb().Max.x - style.ScrollbarWidth, window->Pos.y + window->TitleBarHeight()+1, window->Aabb().Max.x, window->Aabb().Max.y-1); + ImRect bb(window->Rect().Max.x - style.ScrollbarWidth, window->Pos.y + window->TitleBarHeight()+1, window->Rect().Max.x, window->Rect().Max.y-1); window->DrawList->AddRectFilled(bb.Min, bb.Max, window->Color(ImGuiCol_ScrollbarBg)); - bb.Expand(ImVec2(-3,-3)); + bb.Expand(-3.0f); const float scrollbar_height = bb.GetHeight(); // The grabable box size generally represent the amount visible (vs the total scrollable amount) @@ -3751,21 +3804,21 @@ void ImGui::SetCursorPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos = window->Pos + pos; - window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, pos + ImVec2(0.0f, window->ScrollY)); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); } void ImGui::SetCursorPosX(float x) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos.x = window->Pos.x + x; - window->SizeContentsCurrent.x = ImMax(window->SizeContentsCurrent.x, x); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); } void ImGui::SetCursorPosY(float y) { ImGuiWindow* window = GetCurrentWindow(); window->DC.CursorPos.y = window->Pos.y + y; - window->SizeContentsCurrent.y = ImMax(window->SizeContentsCurrent.y, y + window->ScrollY); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); } ImVec2 ImGui::GetCursorScreenPos() @@ -3888,18 +3941,18 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. const char* line = text; const float line_height = ImGui::GetTextLineHeight(); - const ImVec2 start_pos = window->DC.CursorPos; + const ImVec2 text_pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrentLineTextBaseOffset); const ImVec4 clip_rect = window->ClipRectStack.back(); ImVec2 text_size(0,0); - if (start_pos.y <= clip_rect.w) + if (text_pos.y <= clip_rect.w) { - ImVec2 pos = start_pos; + ImVec2 pos = text_pos; // Lines to skip (can't skip when logging text) if (!g.LogEnabled) { - int lines_skippable = (int)((clip_rect.y - start_pos.y) / line_height) - 1; + int lines_skippable = (int)((clip_rect.y - text_pos.y) / line_height) - 1; if (lines_skippable > 0) { int lines_skipped = 0; @@ -3916,11 +3969,11 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // Lines to render if (line < text_end) { - ImGuiAabb line_box(pos, pos + ImVec2(ImGui::GetWindowWidth(), line_height)); + ImRect line_rect(pos, pos + ImVec2(ImGui::GetWindowWidth(), line_height)); while (line < text_end) { const char* line_end = strchr(line, '\n'); - if (IsClipped(line_box)) + if (IsClipped(line_rect)) break; const ImVec2 line_size = CalcTextSize(line, line_end, false); @@ -3929,8 +3982,8 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) if (!line_end) line_end = text_end; line = line_end + 1; - line_box.Min.y += line_height; - line_box.Max.y += line_height; + line_rect.Min.y += line_height; + line_rect.Max.y += line_height; pos.y += line_height; } @@ -3947,9 +4000,10 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) pos.y += lines_skipped * line_height; } - text_size.y += (pos - start_pos).y; + text_size.y += (pos - text_pos).y; } - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + text_size); + + ImRect bb(text_pos, text_pos + text_size); ItemSize(bb); ItemAdd(bb, NULL); } @@ -3957,8 +4011,13 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) { const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); - ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + text_size); - ItemSize(bb.GetSize(), &bb.Min); + + // Account of baseline offset + ImVec2 text_pos = window->DC.CursorPos; + text_pos.y += window->DC.CurrentLineTextBaseOffset; + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(bb.GetSize()); if (!ItemAdd(bb, NULL)) return; @@ -3975,7 +4034,7 @@ void ImGui::AlignFirstTextHeightToWidgets() return; // Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height. - ItemSize(ImVec2(0, window->FontSize() + g.Style.FramePadding.y*2)); + ItemSize(ImVec2(0, window->FontSize() + g.Style.FramePadding.y*2), g.Style.FramePadding.y); ImGui::SameLine(0, 0); } @@ -3994,15 +4053,15 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2, label_size.y)); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2 + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), 0.0f) + label_size); - ItemSize(bb); - if (!ItemAdd(value_bb, NULL)) + const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2, label_size.y + style.FramePadding.y*2)); + const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2 + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, NULL)) return; // Render - RenderTextClipped(value_bb.Min, value_text_begin, value_text_end, NULL, value_bb.Max); - RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y), label); + RenderTextClipped(ImVec2(value_bb.Min.x, value_bb.Min.y + style.FramePadding.y), value_text_begin, value_text_end, NULL, value_bb.Max); + RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); } void ImGui::LabelText(const char* label, const char* fmt, ...) @@ -4013,7 +4072,7 @@ void ImGui::LabelText(const char* label, const char* fmt, ...) va_end(args); } -static bool IsHovered(const ImGuiAabb& bb, ImGuiID id) +static bool IsHovered(const ImRect& bb, ImGuiID id) { ImGuiState& g = *GImGui; if (g.HoveredId == 0) @@ -4021,14 +4080,14 @@ static bool IsHovered(const ImGuiAabb& bb, ImGuiID id) ImGuiWindow* window = GetCurrentWindow(); if (g.HoveredRootWindow == window->RootWindow) { - bool hovered = (g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringBox(bb); + bool hovered = (g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb); return hovered; } } return false; } -static bool ButtonBehavior(const ImGuiAabb& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat, bool pressed_on_click) +static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat, bool pressed_on_click) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -4092,9 +4151,9 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_h const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size + style.FramePadding*2.0f); - ItemSize(bb); + const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : (label_size.x + style.FramePadding.x*2), size_arg.y != 0.0f ? size_arg.y : (label_size.y + style.FramePadding.y*2)); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb, style.FramePadding.y); if (!ItemAdd(bb, &id)) return false; @@ -4106,7 +4165,7 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_h RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); const ImVec2 off = ImVec2(ImMax(0.0f, size.x - label_size.x) * 0.5f, ImMax(0.0f, size.y - label_size.y) * 0.5f); // Center (only applies if we explicitly gave a size bigger than the text size, which isn't the common path) - RenderTextClipped(bb.Min + style.FramePadding + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't the commmon path) + RenderTextClipped(bb.Min + off, label, NULL, &label_size, bb.Max); // Render clip (only applies if we explicitly gave a size smaller than the text size, which isn't the commmon path) return pressed; } @@ -4123,7 +4182,9 @@ bool ImGui::SmallButton(const char* label) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + label_size + ImVec2(style.FramePadding.x*2,0)); + ImVec2 text_pos = window->DC.CursorPos; + text_pos.y += window->DC.CurrentLineTextBaseOffset; + ImRect bb(text_pos, text_pos + label_size + ImVec2(style.FramePadding.x*2,0)); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; @@ -4148,7 +4209,7 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size) return false; const ImGuiID id = window->GetID(str_id); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; @@ -4166,7 +4227,7 @@ static bool CloseWindowButton(bool* p_opened) const ImGuiID id = window->GetID("#CLOSE"); const float size = window->TitleBarHeight() - 4.0f; - const ImGuiAabb bb(window->Aabb().GetTR() + ImVec2(-3.0f-size,2.0f), window->Aabb().GetTR() + ImVec2(-3.0f,2.0f+size)); + const ImRect bb(window->Rect().GetTR() + ImVec2(-3.0f-size,2.0f), window->Rect().GetTR() + ImVec2(-3.0f,2.0f+size)); bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, true); @@ -4195,7 +4256,7 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& if (window->SkipItems) return; - ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); if (border_col.w > 0.0f) bb.Max += ImVec2(2,2); ItemSize(bb); @@ -4233,8 +4294,8 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I ImGui::PopID(); const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2); - const ImGuiAabb image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2); + const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; @@ -4410,7 +4471,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 pos_min = window->DC.CursorPos; const ImVec2 pos_max = window->Pos + GetContentRegionMax(); - ImGuiAabb bb = ImGuiAabb(pos_min, ImVec2(pos_max.x, pos_min.y + label_size.y)); + ImRect bb = ImRect(pos_min, ImVec2(pos_max.x, pos_min.y + label_size.y)); if (display_frame) { bb.Min.x -= window_padding.x*0.5f - 1; @@ -4418,8 +4479,9 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display bb.Max.y += style.FramePadding.y * 2; } - const ImGuiAabb text_bb(bb.Min, bb.Min + ImVec2(window->FontSize() + style.FramePadding.x*2*2,0) + label_size); - ItemSize(ImVec2(text_bb.GetSize().x, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit + // FIXME: we don't provide our width so that it doesn't get feed back into AutoFit. Should manage that better so we can still hover without extending ContentsSize + const ImRect text_bb(bb.Min, bb.Min + ImVec2(window->FontSize() + style.FramePadding.x*2*2,0) + label_size); + ItemSize(ImVec2(text_bb.GetSize().x, bb.GetSize().y), display_frame ? style.FramePadding.y : 0.0f); // When logging is enabled, if automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). // NB- If we are above max depth we still allow manually opened nodes to be logged. @@ -4480,7 +4542,7 @@ void ImGui::Bullet() const ImGuiStyle& style = g.Style; const float line_height = window->FontSize(); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height, line_height)); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height, line_height)); ItemSize(bb); if (!ItemAdd(bb, NULL)) return; @@ -4507,7 +4569,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) const ImGuiStyle& style = g.Style; const float line_height = window->FontSize(); const ImVec2 label_size = CalcTextSize(text_begin, text_end, true); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height + (label_size.x > 0.0f ? (style.FramePadding.x*2) : 0.0f),0) + label_size); // Empty text doesn't add padding + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height + (label_size.x > 0.0f ? (style.FramePadding.x*2) : 0.0f),0) + label_size); // Empty text doesn't add padding ItemSize(bb); if (!ItemAdd(bb, NULL)) return; @@ -4739,7 +4801,7 @@ static void ParseFormat(const char* fmt, int& decimal_precision) } } -static bool SliderBehavior(const ImGuiAabb& frame_bb, const ImGuiAabb& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal) +static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -4749,7 +4811,7 @@ static bool SliderBehavior(const ImGuiAabb& frame_bb, const ImGuiAabb& slider_bb RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); const bool is_finite = (v_min != -FLT_MAX && v_min != FLT_MAX && v_max != -FLT_MAX && v_max != FLT_MAX); - const bool is_non_linear = abs(power - 1.0f) > 0.0001f; + const bool is_non_linear = fabsf(power - 1.0f) > 0.0001f; const float slider_sz = horizontal ? slider_bb.GetWidth() : slider_bb.GetHeight(); float grab_sz; @@ -4867,11 +4929,11 @@ static bool SliderBehavior(const ImGuiAabb& frame_bb, const ImGuiAabb& slider_bb if (!horizontal) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); - ImGuiAabb grab_bb; + ImRect grab_bb; if (horizontal) - grab_bb = ImGuiAabb(ImVec2(grab_pos - grab_sz*0.5f, frame_bb.Min.y + 2.0f), ImVec2(grab_pos + grab_sz*0.5f, frame_bb.Max.y - 2.0f)); + grab_bb = ImRect(ImVec2(grab_pos - grab_sz*0.5f, frame_bb.Min.y + 2.0f), ImVec2(grab_pos + grab_sz*0.5f, frame_bb.Max.y - 2.0f)); else - grab_bb = ImGuiAabb(ImVec2(frame_bb.Min.x + 2.0f, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - 2.0f, grab_pos + grab_sz*0.5f)); + grab_bb = ImRect(ImVec2(frame_bb.Min.x + 2.0f, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - 2.0f, grab_pos + grab_sz*0.5f)); window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, window->Color(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab)); } @@ -4895,14 +4957,14 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImGuiAabb slider_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); // NB- we don't call ItemSize() yet becausae we may turn into a text edit box below - if (!ItemAdd(frame_bb, &id)) + if (!ItemAdd(total_bb, &id)) { - ItemSize(bb); + ItemSize(total_bb, style.FramePadding.y); return false; } @@ -4935,18 +4997,18 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c if (start_text_input || (g.ActiveId == id && id == g.SliderAsInputTextId)) return SliderFloatAsInputText(label, v, id, decimal_precision); - ItemSize(bb); + ItemSize(total_bb, style.FramePadding.y); // Actual slider behavior + render grab - bool value_changed = SliderBehavior(frame_bb, slider_bb, id, v, v_min, v_max, power, decimal_precision, true); + bool value_changed = SliderBehavior(frame_bb, inner_bb, id, v, v_min, v_max, power, decimal_precision, true); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v); const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true); - RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, slider_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); + RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max); - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, slider_bb.Min.y), label); + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); return value_changed; } @@ -4962,11 +5024,11 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); - const ImGuiAabb slider_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect slider_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - ItemSize(bb); + ItemSize(bb, style.FramePadding.y); if (!ItemAdd(frame_bb, &id)) return false; @@ -5019,6 +5081,16 @@ bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const cha return value_changed; } +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format) +{ + if (!display_format) + display_format = "%.0f"; + float v_f = (float)*v; + bool value_changed = ImGui::VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f); + *v = (int)v_f; + return value_changed; +} + // Add multiple sliders on 1 line for compact edition of multiple components static bool SliderFloatN(const char* label, float v[3], int components, float v_min, float v_max, const char* display_format, float power) { @@ -5033,6 +5105,7 @@ static bool SliderFloatN(const char* label, float v[3], int components, float v_ const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -5051,6 +5124,7 @@ static bool SliderFloatN(const char* label, float v[3], int components, float v_ ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -5083,6 +5157,7 @@ static bool SliderIntN(const char* label, int v[3], int components, int v_min, i const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*(components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -5101,6 +5176,7 @@ static bool SliderIntN(const char* label, int v[3], int components, int v_min, i ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -5141,11 +5217,11 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett if (graph_size.y == 0.0f) graph_size.y = label_size.y + (style.FramePadding.y * 2); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y)); - const ImGuiAabb graph_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); - ItemSize(bb); - if (!ItemAdd(bb, NULL)) + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y)); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, NULL)) return; // Determine scale from values if not specified @@ -5173,9 +5249,9 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // Tooltip on hover int v_hovered = -1; - if (IsMouseHoveringBox(graph_bb)) + if (IsMouseHoveringRect(inner_bb)) { - const float t = ImClamp((g.IO.MousePos.x - graph_bb.Min.x) / (graph_bb.Max.x - graph_bb.Min.x), 0.0f, 0.9999f); + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); const int v_idx = (int)(t * (values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0))); IM_ASSERT(v_idx >= 0 && v_idx < values_count); @@ -5207,9 +5283,9 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // NB- Draw calls are merged together by the DrawList system. if (plot_type == ImGuiPlotType_Lines) - window->DrawList->AddLine(ImLerp(graph_bb.Min, graph_bb.Max, p0), ImLerp(graph_bb.Min, graph_bb.Max, p1), v_hovered == v_idx ? col_hovered : col_base); + window->DrawList->AddLine(ImLerp(inner_bb.Min, inner_bb.Max, p0), ImLerp(inner_bb.Min, inner_bb.Max, p1), v_hovered == v_idx ? col_hovered : col_base); else if (plot_type == ImGuiPlotType_Histogram) - window->DrawList->AddRectFilled(ImLerp(graph_bb.Min, graph_bb.Max, p0), ImLerp(graph_bb.Min, graph_bb.Max, ImVec2(p1.x, 1.0f))+ImVec2(-1,0), v_hovered == v_idx ? col_hovered : col_base); + window->DrawList->AddRectFilled(ImLerp(inner_bb.Min, inner_bb.Max, p0), ImLerp(inner_bb.Min, inner_bb.Max, ImVec2(p1.x, 1.0f))+ImVec2(-1,0), v_hovered == v_idx ? col_hovered : col_base); t0 = t1; p0 = p1; @@ -5217,9 +5293,9 @@ static void Plot(ImGuiPlotType plot_type, const char* label, float (*values_gett // Text overlay if (overlay_text) - RenderText(ImVec2(graph_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f, frame_bb.Min.y + style.FramePadding.y), overlay_text); + RenderText(ImVec2(inner_bb.GetCenter().x - ImGui::CalcTextSize(overlay_text, NULL, true).x*0.5f, frame_bb.Min.y + style.FramePadding.y), overlay_text); - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, graph_bb.Min.y), label); + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); } struct ImGuiPlotArrayGetterData @@ -5270,17 +5346,17 @@ bool ImGui::Checkbox(const char* label, bool* v) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); - ItemSize(check_bb); + const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); + ItemSize(check_bb, style.FramePadding.y); - ImGuiAabb total_bb = check_bb; + ImRect total_bb = check_bb; if (label_size.x > 0) SameLine(0, (int)style.ItemInnerSpacing.x); - const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size); + const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size); if (label_size.x > 0) { - ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight())); - total_bb = ImGuiAabb(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max)); + ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); + total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max)); } if (!ItemAdd(total_bb, &id)) @@ -5328,16 +5404,16 @@ bool ImGui::RadioButton(const char* label, bool active) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1)); - ItemSize(check_bb); + const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1)); + ItemSize(check_bb, style.FramePadding.y); - ImGuiAabb total_bb = check_bb; + ImRect total_bb = check_bb; if (label_size.x > 0) SameLine(0, (int)style.ItemInnerSpacing.x); - const ImGuiAabb text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); + const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); if (label_size.x > 0) { - ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight())); + ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); total_bb.Add(text_bb); } @@ -5479,9 +5555,21 @@ void ImGuiTextEditState::UpdateScrollOffset() // Scroll in chunks of quarter width const float scroll_x_increment = Width * 0.25f; const float cursor_offset_x = Font->CalcTextSizeW(FontSize, FLT_MAX, Text, Text+StbState.cursor, NULL).x; - if (ScrollX > cursor_offset_x) + + // If widget became bigger than text (because of a resize), reset horizontal scrolling + if (ScrollX > 0.0f) + { + const float text_width = cursor_offset_x + Font->CalcTextSizeW(FontSize, FLT_MAX, Text+StbState.cursor, NULL, NULL).x; + if (text_width < Width) + { + ScrollX = 0.0f; + return; + } + } + + if (cursor_offset_x < ScrollX) ScrollX = ImMax(0.0f, cursor_offset_x - scroll_x_increment); - else if (ScrollX < cursor_offset_x - Width) + else if (cursor_offset_x - Width >= ScrollX) ScrollX = cursor_offset_x - Width + scroll_x_increment; } @@ -5491,7 +5579,7 @@ ImVec2 ImGuiTextEditState::CalcDisplayOffsetFromCharIdx(int i) const const ImWchar* text_end = (Text+i >= text_start) ? Text+i : text_start; // Clip if requested character is outside of display IM_ASSERT(text_end >= text_start); - const ImVec2 offset = Font->CalcTextSizeW(FontSize, Width, text_start, text_end, NULL); + const ImVec2 offset = Font->CalcTextSizeW(FontSize, Width+1, text_start, text_end, NULL); return offset; } @@ -5524,30 +5612,19 @@ const ImWchar* ImGuiTextEditState::GetTextPointerClippedW(ImFont* font, float fo // [Static] void ImGuiTextEditState::RenderTextScrolledClipped(ImFont* font, float font_size, const char* buf, ImVec2 pos, float width, float scroll_x) { - // NB- We start drawing at character boundary - ImVec2 text_size; - const char* text_start = GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL); - const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width, &text_size); + ImGuiWindow* window = GetCurrentWindow(); + const ImU32 font_color = window->Color(ImGuiCol_Text); + //window->DrawList->AddLine(pos, pos+ImVec2(width,0), 0xFF00FFFF); - // We need to test for the possibility of malformed UTF-8 (instead of just text_end[0] != 0) - unsigned int text_end_char = 0; - ImTextCharFromUtf8(&text_end_char, text_end, NULL); + // Determine start and end of visible string + // FIXME-OPT: This is pretty slow for what it does. + const char* text_start = scroll_x <= 0.0f ? buf : GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL); + const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width + 1, NULL); // +1 to allow character spacing to fit outside the allowed width + window->DrawList->AddText(font, font_size, pos, font_color, text_start, text_end); - // Draw a little clip symbol if we've got text on either left or right of the box - const char symbol_c = '~'; - const float symbol_w = font_size*0.40f; // FIXME: compute correct width - const float clip_begin = (text_start > buf && text_start < text_end) ? symbol_w : 0.0f; - const float clip_end = (text_end_char != 0 && text_end > text_start) ? symbol_w : 0.0f; - - // Draw text - RenderText(pos+ImVec2(clip_begin,0), text_start+(clip_begin>0.0f?1:0), text_end-(clip_end>0.0f?1:0), false); - - // Draw the clip symbol - const char s[2] = {symbol_c,'\0'}; - if (clip_begin > 0.0f) - RenderText(pos, s); - if (clip_end > 0.0f) - RenderText(pos+ImVec2(width-clip_end,0.0f), s); + // Log as text + if (GImGui->LogEnabled) + LogText(pos, buf, NULL); } bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags) @@ -5560,12 +5637,13 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, const ImGuiStyle& style = g.Style; const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + ImGui::BeginGroup(); ImGui::PushID(label); - const float button_sz = window->FontSize(); + const ImVec2 button_sz = ImVec2(window->FontSize(), window->FontSize()) + style.FramePadding * 2; if (step > 0.0f) - ImGui::PushItemWidth(ImMax(1.0f, w - (button_sz + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x)*2)); + ImGui::PushItemWidth(ImMax(1.0f, w - (button_sz.x + style.ItemInnerSpacing.x)*2)); char buf[64]; if (decimal_precision < 0) @@ -5585,13 +5663,13 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, { ImGui::PopItemWidth(); ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (ImGui::Button("-", ImVec2(button_sz,button_sz), true)) + if (ImGui::Button("-", button_sz, true)) { *v -= g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; } ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - if (ImGui::Button("+", ImVec2(button_sz,button_sz), true)) + if (ImGui::Button("+", button_sz, true)) { *v += g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step; value_changed = true; @@ -5603,10 +5681,12 @@ bool ImGui::InputFloat(const char* label, float *v, float step, float step_fast, if (label_size.x > 0) { ImGui::SameLine(0, (int)style.ItemInnerSpacing.x); - ItemSize(label_size); - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label); + ItemSize(label_size, style.FramePadding.y); } + ImGui::EndGroup(); + return value_changed; } @@ -5722,10 +5802,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); - ItemSize(bb); - if (!ItemAdd(frame_bb, &id)) + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, &id)) return false; // NB: we are only allowed to access 'edit_state' if we are the active widget. @@ -5754,7 +5834,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT const char* buf_end = NULL; edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL, &buf_end); edit_state.CurLenA = buf_end - buf; // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. - edit_state.Width = w; + edit_state.Width = w + style.FramePadding.x; edit_state.InputCursorScreenPos = ImVec2(-1.f,-1.f); edit_state.CursorAnimReset(); @@ -5798,16 +5878,21 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT bool cancel_edit = false; bool enter_pressed = false; if (g.ActiveId == id) + //if (edit_state.Id == id) // Works, but double-click to select-all sets cursors to end which in turn tends to scroll toward the right when shrinking widget. { - // Edit in progress + // Update some data if we are active or last active + edit_state.Width = w + style.FramePadding.x; edit_state.BufSizeA = buf_size; edit_state.Font = window->Font(); edit_state.FontSize = window->FontSize(); - + edit_state.UpdateScrollOffset(); + } + if (g.ActiveId == id) + { + // Edit in progress const float mx = g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x; const float my = window->FontSize()*0.5f; // Flatten mouse because we are doing a single-line edit - edit_state.UpdateScrollOffset(); if (select_all || (hovered && io.MouseDoubleClicked[0])) { edit_state.SelectAll(); @@ -5817,7 +5902,6 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT { stb_textedit_click(&edit_state, &edit_state.StbState, mx + edit_state.ScrollX, my); edit_state.CursorAnimReset(); - } else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock) { @@ -6008,7 +6092,9 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT } } - ImGuiTextEditState::RenderTextScrolledClipped(window->Font(), window->FontSize(), buf, frame_bb.Min + style.FramePadding, w, (g.ActiveId == id) ? edit_state.ScrollX : 0.0f); + //const float render_scroll_x = (g.ActiveId == id) ? edit_state.ScrollX : 0.0f; + const float render_scroll_x = (edit_state.Id == id) ? edit_state.ScrollX : 0.0f; + ImGuiTextEditState::RenderTextScrolledClipped(window->Font(), window->FontSize(), buf, frame_bb.Min + style.FramePadding, w + style.FramePadding.x, render_scroll_x); if (g.ActiveId == id) { @@ -6047,6 +6133,7 @@ static bool InputFloatN(const char* label, float* v, int components, int decimal const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -6064,7 +6151,9 @@ static bool InputFloatN(const char* label, float* v, int components, int decimal ImGui::PopItemWidth(); ImGui::PopID(); + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, style.FramePadding.y); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -6097,6 +6186,7 @@ static bool InputIntN(const char* label, int* v, int components) const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1))); bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); ImGui::PushItemWidth(w_item_one); for (int i = 0; i < components; i++) @@ -6115,6 +6205,7 @@ static bool InputIntN(const char* label, int* v, int components) ImGui::PopID(); ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); + ImGui::EndGroup(); return value_changed; } @@ -6196,17 +6287,17 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const float w = ImGui::CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(style.ItemInnerSpacing.x + label_size.x,0)); - ItemSize(bb); - if (!ItemAdd(frame_bb, &id)) + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(style.ItemInnerSpacing.x + label_size.x,0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, &id)) return false; const float arrow_size = (window->FontSize() + style.FramePadding.x * 2.0f); const bool hovered = IsHovered(frame_bb, id); bool value_changed = false; - const ImGuiAabb value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); + const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding); RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, window->Color(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING RenderCollapseTriangle(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y) + style.FramePadding, true); @@ -6244,11 +6335,11 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi const ImVec2 backup_pos = ImGui::GetCursorPos(); const float popup_off_x = 0.0f;//style.ItemInnerSpacing.x; const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + style.WindowPadding.y; - const ImGuiAabb popup_aabb(ImVec2(frame_bb.Min.x+popup_off_x, frame_bb.Max.y), ImVec2(frame_bb.Max.x+popup_off_x, frame_bb.Max.y + popup_height)); - ImGui::SetCursorPos(popup_aabb.Min - window->Pos); + const ImRect popup_rect(ImVec2(frame_bb.Min.x+popup_off_x, frame_bb.Max.y), ImVec2(frame_bb.Max.x+popup_off_x, frame_bb.Max.y + popup_height)); + ImGui::SetCursorPos(popup_rect.Min - window->Pos); const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0); - ImGui::BeginChild("#ComboBox", popup_aabb.GetSize(), false, flags); + ImGui::BeginChild("#ComboBox", popup_rect.GetSize(), false, flags); ImGui::Spacing(); bool combo_item_active = false; @@ -6301,11 +6392,11 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const float w = window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x; const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); // Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing. - ImGuiAabb bb_with_spacing = bb; + ImRect bb_with_spacing = bb; const float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f); const float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f); const float spacing_R = style.ItemSpacing.x - spacing_L; @@ -6355,13 +6446,14 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. ImVec2 size; - size.x = (size_arg.x != 0.0f) ? size_arg.x : ImGui::CalcItemWidth() + style.FramePadding.x * 2.0f; - size.y = (size_arg.y != 0.0f) ? size_arg.y : ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y; + size.x = (size_arg.x != 0.0f) ? (size_arg.x) : ImGui::CalcItemWidth() + style.FramePadding.x * 2.0f; + size.y = (size_arg.y != 0.0f) ? (size_arg.y) : ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y; const ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); - const ImGuiAabb frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); - const ImGuiAabb bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - window->DC.LastItemAabb = bb; + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + window->DC.LastItemRect = bb; + ImGui::BeginGroup(); if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -6388,12 +6480,17 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item void ImGui::ListBoxFooter() { ImGuiWindow* parent_window = GetParentWindow(); - const ImGuiAabb bb = parent_window->DC.LastItemAabb; + const ImRect bb = parent_window->DC.LastItemRect; + const ImGuiStyle& style = ImGui::GetStyle(); ImGui::EndChildFrame(); + // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) + // We call SameLine() to restore DC.CurrentLine* data + ImGui::SameLine(); parent_window->DC.CursorPos = bb.Min; - ItemSize(bb, NULL); + ItemSize(bb, style.FramePadding.y); + ImGui::EndGroup(); } bool ImGui::ListBox(const char* label, int* current_item, const char** items, int items_count, int height_items) @@ -6443,8 +6540,8 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID("#colorbutton"); const float square_size = window->FontSize(); - const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2))); - ItemSize(bb); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.x*2, square_size + (small_height ? 0 : style.FramePadding.y*2))); + ItemSize(bb, small_height ? 0.0f : style.FramePadding.y); if (!ItemAdd(bb, &id)) return false; @@ -6513,6 +6610,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) int components = alpha ? 4 : 3; bool value_changed = false; + ImGui::BeginGroup(); ImGui::PushID(label); bool hsv = (edit_mode == 1); @@ -6617,6 +6715,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) } ImGui::PopID(); + ImGui::EndGroup(); return value_changed; } @@ -6637,7 +6736,7 @@ void ImGui::Separator() if (window->DC.ColumnsCount > 1) PopClipRect(); - const ImGuiAabb bb(ImVec2(window->Pos.x, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x, window->DC.CursorPos.y)); + const ImRect bb(ImVec2(window->Pos.x, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x, window->DC.CursorPos.y)); ItemSize(ImVec2(0.0f, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit if (!ItemAdd(bb, NULL)) { @@ -6670,38 +6769,39 @@ void ImGui::Spacing() } // Advance cursor given item size. -static void ItemSize(ImVec2 size, ImVec2* adjust_vertical_offset) +static void ItemSize(ImVec2 size, float text_offset_y) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); - if (adjust_vertical_offset) - adjust_vertical_offset->y = adjust_vertical_offset->y + (line_height - size.y) * 0.5f; - // Always align ourselves on pixel boundaries + const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); + const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); - window->SizeContentsCurrent = ImMax(window->SizeContentsCurrent, ImVec2(window->DC.CursorPosPrevLine.x - window->Pos.x, window->DC.CursorPos.y + window->ScrollY - window->Pos.y)); + //window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, 0xFF0000FF, 4); // Debug window->DC.PrevLineHeight = line_height; - window->DC.CurrentLineHeight = 0.0f; + window->DC.PrevLineTextBaseOffset = text_base_offset; + window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f; } -static inline void ItemSize(const ImGuiAabb& bb, ImVec2* adjust_start_offset) +static inline void ItemSize(const ImRect& bb, float text_offset_y) { - ItemSize(bb.GetSize(), adjust_start_offset); + ItemSize(bb.GetSize(), text_offset_y); } -static bool IsClipped(const ImGuiAabb& bb) +static bool IsClipped(const ImRect& bb) { ImGuiState& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - if (!bb.Overlaps(ImGuiAabb(window->ClipRectStack.back())) && !g.LogEnabled) + if (!bb.Overlaps(ImRect(window->ClipRectStack.back())) && !g.LogEnabled) return true; return false; } @@ -6709,27 +6809,87 @@ static bool IsClipped(const ImGuiAabb& bb) bool ImGui::IsClipped(const ImVec2& item_size) { ImGuiWindow* window = GetCurrentWindow(); - return IsClipped(ImGuiAabb(window->DC.CursorPos, window->DC.CursorPos + item_size)); + return IsClipped(ImRect(window->DC.CursorPos, window->DC.CursorPos + item_size)); } -static bool ItemAdd(const ImGuiAabb& bb, const ImGuiID* id) +static bool ItemAdd(const ImRect& bb, const ImGuiID* id) { ImGuiWindow* window = GetCurrentWindow(); window->DC.LastItemID = id ? *id : 0; - window->DC.LastItemAabb = bb; + window->DC.LastItemRect = bb; if (IsClipped(bb)) { - window->DC.LastItemHovered = false; + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRectOnly = false; return false; } // This is a sensible default, but widgets are free to override it after calling ItemAdd() - const bool hovered = IsMouseHoveringBox(bb); - //const bool hovered = (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly) && IsMouseHoveringBox(bb); // matching the behavior of IsHovered(), not always what the user wants? - window->DC.LastItemHovered = hovered; + ImGuiState& g = *GImGui; + if (IsMouseHoveringRect(bb)) + { + // Matching the behavior of IsHovered() but ignore if ActiveId==window->MoveID (we clicked on the window background) + // So that clicking on items with no active id such as Text() still returns true with IsItemHovered() + window->DC.LastItemHoveredRectOnly = true; + if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly || (g.ActiveId == window->MoveID)) + window->DC.LastItemHoveredAndUsable = true; + else + window->DC.LastItemHoveredAndUsable = false; + } + else + { + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRectOnly = false; + } + return true; } +void ImGui::BeginGroup() +{ + ImGuiWindow* window = GetCurrentWindow(); + + window->DC.GroupStack.resize(window->DC.GroupStack.size() + 1); + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupColumnsStartX = window->DC.ColumnsStartX; + group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight; + group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; + group_data.BackupLogLinePosY = window->DC.LogLinePosY; + + window->DC.ColumnsStartX = window->DC.CursorPos.x - window->Pos.x; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrentLineHeight = 0.0f; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; +} + +void ImGui::EndGroup() +{ + ImGuiWindow* window = GetCurrentWindow(); + ImGuiStyle& style = ImGui::GetStyle(); + + IM_ASSERT(!window->DC.GroupStack.empty()); + + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + + ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); + group_bb.Max.y -= style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves. + group_bb.Max = ImMax(group_bb.Min, group_bb.Max); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight; + window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; // FIXME: Ideally we'll grab the base offset from the first line of the group. + window->DC.ColumnsStartX = group_data.BackupColumnsStartX; + window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; + + ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset); + ItemAdd(group_bb, NULL); + + window->DC.GroupStack.pop_back(); + + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug +} + // Gets back to previous line and continue with horizontal layout // column_x == 0 : follow on previous item // columm_x != 0 : align to specified column @@ -6756,6 +6916,7 @@ void ImGui::SameLine(int column_x, int spacing_w) y = window->DC.CursorPosPrevLine.y; } window->DC.CurrentLineHeight = window->DC.PrevLineHeight; + window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; window->DC.CursorPos = ImVec2(x, y); } @@ -6785,6 +6946,7 @@ void ImGui::NextColumn() window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX); window->DC.CursorPos.y = window->DC.ColumnsCellMinY; window->DC.CurrentLineHeight = 0.0f; + window->DC.CurrentLineTextBaseOffset = 0.0f; PushColumnClipRect(); ImGui::PushItemWidth(ImGui::GetColumnWidth() * 0.65f); @@ -6884,13 +7046,13 @@ void ImGui::Columns(int columns_count, const char* id, bool border) float x = window->Pos.x + GetColumnOffset(i); const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i); - const ImGuiAabb column_aabb(ImVec2(x-4,y1),ImVec2(x+4,y2)); + const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2)); - if (IsClipped(column_aabb)) + if (IsClipped(column_rect)) continue; bool hovered, held; - ButtonBehavior(column_aabb, column_id, &hovered, &held, true); + ButtonBehavior(column_rect, column_id, &hovered, &held, true); // Draw before resize so our items positioning are in sync with the line being drawn const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column); @@ -7093,6 +7255,18 @@ void ImDrawList::PushClipRect(const ImVec4& clip_rect) UpdateClipRect(); } +void ImDrawList::PushClipRectFullScreen() +{ + PushClipRect(GNullClipRect); + + // This would be more correct but we're not supposed to access ImGuiState from here? + //ImGuiState& g = *GImGui; + //if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y) + // PushClipRect(ImVec4(g.IO.DisplayVisibleMin.x, g.IO.DisplayVisibleMin.y, g.IO.DisplayVisibleMax.x, g.IO.DisplayVisibleMax.y)); + //else + // PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); +} + void ImDrawList::PopClipRect() { IM_ASSERT(clip_rect_stack.size() > 0); @@ -7400,13 +7574,14 @@ void ImDrawList::Rect(const ImVec2& a, const ImVec2& b, float rounding, int roun } } -void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col) +void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float half_thickness) { if ((col >> 24) == 0) return; LineTo(a); LineTo(b); - Stroke(col); + Stroke(col, false); + (void)half_thickness; } void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners) @@ -7451,7 +7626,7 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, Fill(col); } -void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec2* cpu_clip_max) +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec2* cpu_clip_max) { if ((col >> 24) == 0) return; @@ -8359,6 +8534,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte) + const char* prev_s = s; unsigned int c = (unsigned int)*s; if (c < 0x80) { @@ -8381,7 +8557,10 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; if (line_width + char_width >= max_width) + { + s = prev_s; break; + } line_width += char_width; } @@ -8425,7 +8604,10 @@ ImVec2 ImFont::CalcTextSizeW(float size, float max_width, const ImWchar* text_be const float char_width = ((size_t)c < IndexXAdvance.size()) ? IndexXAdvance[(size_t)c] * scale : FallbackXAdvance; if (line_width + char_width >= max_width) + { + s--; break; + } line_width += char_width; } @@ -8995,14 +9177,14 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetCursorScreenPos() + ImVec2(wrap_width, 0.0f), ImGui::GetCursorScreenPos() + ImVec2(wrap_width+10, ImGui::GetTextLineHeight()), 0xFFFF00FF); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); ImGui::Text("lazy dog. This paragraph is made to fit within %.0f pixels. The quick brown fox jumps over the lazy dog.", wrap_width); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemBoxMin(), ImGui::GetItemBoxMax(), 0xFF00FFFF); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), 0xFF00FFFF); ImGui::PopTextWrapPos(); ImGui::Text("Test paragraph 2:"); ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetCursorScreenPos() + ImVec2(wrap_width, 0.0f), ImGui::GetCursorScreenPos() + ImVec2(wrap_width+10, ImGui::GetTextLineHeight()), 0xFFFF00FF); ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); ImGui::Text("aaaaaaaa bbbbbbbb, cccccccc,dddddddd. eeeeeeee ffffffff. gggggggg!hhhhhhhh"); - ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemBoxMin(), ImGui::GetItemBoxMax(), 0xFF00FFFF); + ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), 0xFF00FFFF); ImGui::PopTextWrapPos(); ImGui::TreePop(); @@ -9171,6 +9353,8 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Separator(); + ImGui::LabelText("label", "Value"); + static int item = 1; ImGui::Combo("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); @@ -9249,12 +9433,18 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Vertical Sliders")) { ImGui::Unindent(); + const float spacing = 4; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + static int int_value = 0; + ImGui::VSliderInt("##int", ImVec2(18,160), &int_value, 0, 5); + ImGui::SameLine(); static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; ImGui::PushID("set1"); for (int i = 0; i < 7; i++) { - if (i > 0) ImGui::SameLine(0, 4); + if (i > 0) ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImColor::HSV(i/7.0f, 0.5f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImColor::HSV(i/7.0f, 0.9f, 0.9f)); @@ -9268,11 +9458,31 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::PopID(); ImGui::SameLine(); - ImGui::PushID("set2"); + static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + const int rows = 3; + const ImVec2 small_slider_size(18, (160.0f-(rows-1)*spacing)/rows); + for (int nx = 0; nx < 4; nx++) + { + if (nx > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + for (int ny = 0; ny < rows; ny++) + { + ImGui::PushID(nx*rows+ny); + ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values2[nx]); + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set3"); for (int i = 0; i < 4; i++) { - if (i > 0) ImGui::SameLine(0, 4); + if (i > 0) ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f"); @@ -9284,6 +9494,26 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Indent(); ImGui::TreePop(); } + + if (ImGui::TreeNode("Dragging")) + { + // You can use ImGui::GetItemActiveDragDelta() to query for the dragged amount on any widget. + static ImVec2 value(0.0f, 0.0f); + ImGui::Button("Drag Me"); + if (ImGui::IsItemActive()) + { + value = ImGui::GetItemActiveDragDelta(); + //ImGui::SetTooltip("Delta: %.1f, %.1f", value.x, value.y); + + // Draw a line between the button and the mouse cursor + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->PushClipRectFullScreen(); + draw_list->AddLine(ImGui::CalcItemRectClosestPoint(ImGui::GetIO().MousePos, true, -2.0f), ImGui::GetIO().MousePos, ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), 2.0f); + draw_list->PopClipRect(); + } + ImGui::SameLine(); ImGui::Text("Value: %.1f, %.1f", value.x, value.y); + ImGui::TreePop(); + } } if (ImGui::CollapsingHeader("Graphs widgets")) @@ -9292,7 +9522,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); static bool pause; - static ImVector values; if (values.empty()) { values.resize(100); memset(&values.front(), 0, values.size()*sizeof(float)); } + static ImVector values; if (values.empty()) { values.resize(90); memset(&values.front(), 0, values.size()*sizeof(float)); } static size_t values_offset = 0; if (!pause) { @@ -9307,69 +9537,183 @@ void ImGui::ShowTestWindow(bool* opened) phase += 0.10f*values_offset; } } - ImGui::PlotLines("Frame Times", &values.front(), (int)values.size(), (int)values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); - - ImGui::SameLine(); ImGui::Checkbox("pause", &pause); + ImGui::PlotLines("##Graph", &values.front(), (int)values.size(), (int)values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80)); + ImGui::SameLine(0, (int)ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::BeginGroup(); + ImGui::Text("Graph"); + ImGui::Checkbox("pause", &pause); + ImGui::EndGroup(); ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80)); } - if (ImGui::CollapsingHeader("Horizontal Layout")) + if (ImGui::CollapsingHeader("Layout")) { - // Text - ImGui::Text("Hello"); - ImGui::SameLine(); - ImGui::Text("World"); - - // Button - if (ImGui::Button("Banana")) printf("Pressed!\n"); - ImGui::SameLine(); - ImGui::Button("Apple"); - ImGui::SameLine(); - ImGui::Button("Corniflower"); - - // Button - ImGui::Text("Small buttons"); - ImGui::SameLine(); - ImGui::SmallButton("Like this one"); - ImGui::SameLine(); - ImGui::Text("can fit within a text block."); - - // Checkbox - static bool c1=false,c2=false,c3=false,c4=false; - ImGui::Checkbox("My", &c1); - ImGui::SameLine(); - ImGui::Checkbox("Tailor", &c2); - ImGui::SameLine(); - ImGui::Checkbox("Is", &c3); - ImGui::SameLine(); - ImGui::Checkbox("Rich", &c4); - - // Various - static float f0=1.0f, f1=2.0f, f2=3.0f; - ImGui::PushItemWidth(80); - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; - static int item = -1; - ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); - ImGui::SameLine(); - ImGui::SliderFloat("X", &f0, 0.0f,5.0f); - ImGui::SameLine(); - ImGui::SliderFloat("Y", &f1, 0.0f,5.0f); - ImGui::SameLine(); - ImGui::SliderFloat("Z", &f2, 0.0f,5.0f); - ImGui::PopItemWidth(); - - ImGui::PushItemWidth(80); - ImGui::Text("Lists:"); - static int selection[4] = { 0, 1, 2, 3 }; - for (int i = 0; i < 4; i++) + if (ImGui::TreeNode("Widgets Alignment")) { - if (i > 0) ImGui::SameLine(); - ImGui::PushID(i); - ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); - ImGui::PopID(); - //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + static float f = 0.0f; + ImGui::Text("Fixed: 100 pixels"); + ImGui::PushItemWidth(100); + ImGui::InputFloat("float##1", &f); + ImGui::PopItemWidth(); + + ImGui::Text("Proportional: 50%% of window width"); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); + ImGui::InputFloat("float##2", &f); + ImGui::PopItemWidth(); + + ImGui::Text("Right-aligned: Leave 100 pixels for label"); + ImGui::PushItemWidth(-100); + ImGui::InputFloat("float##3", &f); + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Basic Horizontal Layout")) + { + ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceeding item)"); + + // Text + ImGui::Text("Two items: Hello"); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(1,1,0,1), "World"); + + // Adjust spacing + ImGui::Text("More spacing: Hello"); + ImGui::SameLine(0, 20); + ImGui::TextColored(ImVec4(1,1,0,1), "World"); + + // Button + ImGui::AlignFirstTextHeightToWidgets(); + ImGui::Text("Normal buttons"); ImGui::SameLine(); + ImGui::Button("Banana"); ImGui::SameLine(); + ImGui::Button("Apple"); ImGui::SameLine(); + ImGui::Button("Corniflower"); + + // Button + ImGui::Text("Small buttons"); ImGui::SameLine(); + ImGui::SmallButton("Like this one"); ImGui::SameLine(); + ImGui::Text("can fit within a text block."); + + // Aligned to arbitrary position. Easy/cheap column. + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::Text("x=150"); + ImGui::SameLine(300); ImGui::Text("x=300"); + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::SmallButton("x=150"); + ImGui::SameLine(300); ImGui::SmallButton("x=300"); + + // Checkbox + static bool c1=false,c2=false,c3=false,c4=false; + ImGui::Checkbox("My", &c1); ImGui::SameLine(); + ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); + ImGui::Checkbox("Is", &c3); ImGui::SameLine(); + ImGui::Checkbox("Rich", &c4); + + // Various + static float f0=1.0f, f1=2.0f, f2=3.0f; + ImGui::PushItemWidth(80); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; + static int item = -1; + ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); + ImGui::SliderFloat("X", &f0, 0.0f,5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Y", &f1, 0.0f,5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Z", &f2, 0.0f,5.0f); + ImGui::PopItemWidth(); + + ImGui::PushItemWidth(80); + ImGui::Text("Lists:"); + static int selection[4] = { 0, 1, 2, 3 }; + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); + ImGui::PopID(); + //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + } + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Groups")) + { + ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items)"); + + ImVec2 size; + ImGui::BeginGroup(); + { + ImGui::BeginGroup(); + ImGui::Button("AAA"); + ImGui::SameLine(); + ImGui::Button("BBB"); + ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Button("CCC"); + ImGui::Button("DDD"); + ImGui::EndGroup(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Group hovered"); + ImGui::SameLine(); + ImGui::Button("EEE"); + ImGui::EndGroup(); + + // Capture the group size and create widgets using the same size + size = ImGui::GetItemRectSize(); + const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; + ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); + } + ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f,size.y)); + ImGui::SameLine(); + ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f,size.y)); + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::Button("LEVERAGE\nBUZZWORD", size); + ImGui::SameLine(); + + ImGui::ListBoxHeader("List", size); + ImGui::Selectable("Selected", true); + ImGui::Selectable("Not Selected", false); + ImGui::ListBoxFooter(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text Baseline Alignment")) + { + ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)"); + + ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("One\nTwo\nThree"); + + ImGui::Button("HOP"); ImGui::SameLine(); + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("HOP"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("TEST"); ImGui::SameLine(); + ImGui::Text("TEST"); ImGui::SameLine(); + ImGui::SmallButton("TEST"); + + ImGui::AlignFirstTextHeightToWidgets(); // If your line starts with text, call this to align it to upcoming widgets. + ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); + ImGui::Button("Widget"); ImGui::SameLine(); + ImGui::Text("Widget"); ImGui::SameLine(); + ImGui::SmallButton("Widget"); + + ImGui::TreePop(); } - ImGui::PopItemWidth(); } if (ImGui::CollapsingHeader("Child regions")) @@ -9415,6 +9759,7 @@ void ImGui::ShowTestWindow(bool* opened) // Basic columns ImGui::Text("Basic:"); ImGui::Columns(4, "mycolumns"); + ImGui::Separator(); ImGui::Text("ID"); ImGui::NextColumn(); ImGui::Text("Name"); ImGui::NextColumn(); ImGui::Text("Path"); ImGui::NextColumn(); @@ -9641,13 +9986,13 @@ static void ShowExampleAppAutoResize(bool* opened) static void ShowExampleAppFixedOverlay(bool* opened) { + ImGui::SetNextWindowPos(ImVec2(10,10)); if (!ImGui::Begin("Example: Fixed Overlay", opened, ImVec2(0,0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings)) { ImGui::End(); return; } - ImGui::SetWindowPos(ImVec2(10,10)); ImGui::Text("Simple overlay\non the top-left side of the screen."); ImGui::Separator(); ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); diff --git a/imgui.h b/imgui.h index e7fdbfb66..fba967277 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.36 WIP +// ImGui library v1.37 WIP // See .cpp file for documentation. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. @@ -13,7 +13,7 @@ #include // NULL, malloc #include // memset, memmove -#define IMGUI_VERSION "1.36 WIP" +#define IMGUI_VERSION "1.37 WIP" // Define assertion handler. #ifndef IM_ASSERT @@ -223,8 +223,10 @@ namespace ImGui IMGUI_API void EndTooltip(); // Layout + IMGUI_API void BeginGroup(); + IMGUI_API void EndGroup(); IMGUI_API void Separator(); // horizontal line - IMGUI_API void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets to layout them horizontally + IMGUI_API void SameLine(int column_x = 0, int spacing_w = -1); // call between widgets or groups to layout them horizontally IMGUI_API void Spacing(); // add vertical spacing IMGUI_API void Indent(); // move content position toward the right by style.IndentSpacing pixels IMGUI_API void Unindent(); // move content position back to the left (cancel Indent) @@ -286,6 +288,7 @@ namespace ImGui IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f"); IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f"); IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f"); IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float)); @@ -349,25 +352,29 @@ namespace ImGui // Utilities IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? + IMGUI_API bool IsItemHoveredRectOnly(); // was the last item hovered by mouse? even if another item is active while we are hovering this. IMGUI_API bool IsItemActive(); // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) IMGUI_API bool IsAnyItemActive(); // + IMGUI_API ImVec2 GetItemActiveDragDelta(); // mouse delta from the time the item first got active + IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item + IMGUI_API ImVec2 GetItemRectMax(); // " + IMGUI_API ImVec2 GetItemRectSize(); // " IMGUI_API bool IsWindowFocused(); // is current window focused (differentiate child windows from each others) IMGUI_API bool IsRootWindowFocused(); // is current root window focused IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused - IMGUI_API ImVec2 GetItemBoxMin(); // get bounding box of last item - IMGUI_API ImVec2 GetItemBoxMax(); // get bounding box of last item IMGUI_API bool IsClipped(const ImVec2& item_size); // to perform coarse clipping on user's side (as an optimization) IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry IMGUI_API bool IsMouseClicked(int button, bool repeat = false); IMGUI_API bool IsMouseDoubleClicked(int button); IMGUI_API bool IsMouseHoveringWindow(); // is mouse hovering current window ("window" in API names always refer to current window) IMGUI_API bool IsMouseHoveringAnyWindow(); // is mouse hovering any active imgui window - IMGUI_API bool IsMouseHoveringBox(const ImVec2& box_min, const ImVec2& box_max); // is mouse hovering given bounding box + IMGUI_API bool IsMouseHoveringRect(const ImVec2& rect_min, const ImVec2& rect_max);// is mouse hovering given bounding rect IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); IMGUI_API const char* GetStyleColName(ImGuiCol idx); + IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items. IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of items. see comments in implementation. @@ -385,9 +392,12 @@ namespace ImGui IMGUI_API void SetInternalState(void* state, bool construct = false); // Obsolete (will be removed) - IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); - static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } - static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } + IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); // OBSOLETE + static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpened(open, 0); } // OBSOLETE + static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE + static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE + static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE + static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE } // namespace ImGui @@ -542,13 +552,14 @@ struct ImGuiStyle float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) - ImVec2 TouchExtraPadding; // Expand bounding box for touch-based system where touch position is not accurate enough (unnecessary for mouse inputs). Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget running. So dont grow this too much! + ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! ImVec2 AutoFitPadding; // Extra space after auto-fit (double-clicking on resize grip) float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin() float IndentSpacing; // Horizontal indentation when e.g. entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarWidth; // Width of the vertical scrollbar float GrabMinSize; // Minimum width/height of a slider or scrollbar grab + ImVec2 DisplaySafeAreaPadding; // Window positions are clamped to be visible within the display area. If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. ImVec4 Colors[ImGuiCol_COUNT]; IMGUI_API ImGuiStyle(); @@ -853,6 +864,7 @@ struct ImDrawList ImDrawList() { Clear(); } IMGUI_API void Clear(); IMGUI_API void PushClipRect(const ImVec4& clip_rect); // Scissoring. The values are x1, y1, x2, y2. + IMGUI_API void PushClipRectFullScreen(); IMGUI_API void PopClipRect(); IMGUI_API void PushTextureID(const ImTextureID& texture_id); IMGUI_API void PopTextureID(); @@ -867,13 +879,13 @@ struct ImDrawList IMGUI_API void Stroke(ImU32 col, bool closed = false); // Primitives - IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col); + IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float half_thickness = 0.50f); IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners=0x0F); IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners=0x0F); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); - IMGUI_API void AddText(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 ImVec2* cpu_clip_max = NULL); + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec2* cpu_clip_max = NULL); IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col = 0xFFFFFFFF); IMGUI_API void AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed); IMGUI_API void AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col); @@ -886,7 +898,6 @@ struct ImDrawList IMGUI_API void ReserveVertices(unsigned int vtx_count); IMGUI_API void AddVtx(const ImVec2& pos, ImU32 col); IMGUI_API void AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv); - IMGUI_API void AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col); IMGUI_API void UpdateClipRect(); IMGUI_API void UpdateTextureID(); };