diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..3dd05d3d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,20 @@
+# editorconfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Default settings:
+# Use 4 spaces as indentation
+[*]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[imstb_*]
+indent_size = 3
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
+indent_size = 4
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
deleted file mode 100644
index 4fe220b9..00000000
--- a/.github/CONTRIBUTING.md
+++ /dev/null
@@ -1,42 +0,0 @@
-## How to create an Issue
-
-Hello!
-
-You may use the Issue Tracker to submit bug reports, feature requests or suggestions. You may ask for help or advice as well. However please read this wall of text before doing so. The amount of incomplete or ambiguous requests due to people not following those guidelines is often overwhelming. Please do your best to clarify your request. Thank you!
-
-**IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/DISPLAYING/ADDING FONTS/WIRING INPUTS**
-- Please post on the "Getting Started" Discourse forum: https://discourse.dearimgui.org/c/getting-started
-
-**Prerequisites for new users of dear imgui:**
-- Please read the FAQ in imgui.cpp.
-- Please read misc/fonts/README.txt if your question relates to fonts or text.
-- Please run ImGui::ShowDemoWindow() to explore the demo and its sources.
-- Please use the Search function of GitHub to look for similar issues. You may also browse issues by tags.
-- Please use the Search function of your IDE to search in the code for comments related to your situation.
-- If you get a assert, use a debugger to locate the line triggering it and read the comments around the assert.
-
-**Guidelines to report an issue or ask a question:**
-- Please provide your imgui version number.
-- Please state if you have made substantial modifications to your copy of imgui.
-- Try to be explicit with your Goals, your Expectations and what you have Tried. What you have in mind or in your code is not obvious to other people. People frequently discuss problems without first mentioning their goal.
-- If you are discussing an assert or a crash, please provide a debugger callstack. Never state "it crashes" without additional information. If you don't know how to use a debugger and retrieve a callstack, learning about it will be useful.
-- Please make sure that your compilation settings have asserts enabled. Calls to IM_ASSERT() are scattered in the code to help catch common issues. By default IM_ASSERT() calls the standard assert() function. To verify that your asserts are enabled, add the line `IM_ASSERT(false);` in your main() function. Your application should display an error message and abort. If your application report an error, it means that your asserts are disabled. Please make sure they are enabled.
-- When discussing issues related to rendering or inputs, please state the OS/back-end/renderer you are using. Please state if you are using a vanilla copy of the example back-ends (imgui_impl_XXX files), or a modified one, or if you built your own.
-- Please provide a Minimal, Complete and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem. An ideal submission includes a small piece of code that anyone can paste in one of the examples/ application (e.g. in main.cpp or imgui_demo.cpp) to understand and reproduce it. Narrowing your problem to its shortest and purest form is the easiest way to understand it. Please test your shortened code to ensure it actually exhibit the problem. Often while creating the MCVE you will end up solving the problem! Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time.
-- Try to attach screenshots to clarify the context. They often convey useful information that are omitted by the description. You can drag pictures/files here (prefer github attachments over 3rd party hosting).
-- When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc.).
-
-**Some unfortunate words of warning**
-- If you are or were involved in cheating schemes (e.g. DLL injection) for competitive online multi-player games, please don't post here. We won't answer and you will be blocked. We've had too many of you.
-- Due to frequent abuse of this service from aforementioned users, if your GitHub account is anonymous and was created five minutes ago please understand that your post will receive more scrutiny and incomplete questions may be dismissed.
-
-If you have been using dear imgui for a while or have been using C/C++ for several years or have demonstrated good behavior here, it is ok to not fullfill every item to the letter. Those are guidelines and experienced users or members of the community will know which information are useful in a given context.
-
-## How to create an Pull Request
-- When adding a feature, please describe the usage context (how you intend to use it, why you need it, etc.).
-- When fixing a warning or compilation problem, please post the compiler log and specify the version and OS you are using.
-- Try to attach screenshots to clarify the context and demonstrate the feature at a glance. You can drag pictures/files here (prefer github attachments over 3rd party hosting).
-- Make sure your code follows the coding style already used in imgui (spaces instead of tabs, "local_variable", "FunctionName", "MemberName", etc.). We don't use modern C++ idioms and can compile without C++11.
-- Make sure you create a branch for the pull request. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR (we can still cherry-pick individual commits).
-
-Thank you for reading!
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100644
index 05c68ea6..00000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,8 +0,0 @@
-- Please read https://github.com/ocornut/imgui/blob/master/.github/CONTRIBUTING.md
-- When adding a feature, please describe the usage context (how you intend to use it, why you need it, etc.).
-- When adding a feature, try to attach screenshots/gifs to clarify the context and demonstrate the feature at a glance.
-- When fixing a warning or compilation problem, post the compiler log and specify the version and OS you are using.
-- Make sure your code follows the coding style already used in the codebase (4 spaces identation, no tabs, `type* name`, `local_variable`, `FunctionName()`, `MemberName`, `// Text Comment`, `//CodeComment()`, etc.). We don't use modern C++ idioms, we don't use C++ style cast, we don't use C++ headers, and we can compile without a C++11 compatible compiler.
-- Make sure you create a branch for the pull request. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR.
-
-(Clear this form before submitting your PR)
diff --git a/LICENSE.txt b/LICENSE.txt
index 21b6ee7e..3b439aa4 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2014-2018 Omar Cornut
+Copyright (c) 2014-2019 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index b32c9147..b4669fb1 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -12,7 +12,7 @@ COMMITS HISTORY: https://github.com/ocornut/imgui/commits/master
WHEN TO UPDATE?
- Keeping your copy of dear imgui updated once in a while is recommended.
-- It is generally safe to sync to the latest commit in master.
+- It is generally safe to sync to the latest commit in master.
The library is fairly stable and regressions tends to be fixed fast when reported.
HOW TO UPDATE?
@@ -23,8 +23,8 @@ HOW TO UPDATE?
- If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it.
- If you are dropping this repository in your codebase, please leave the demo and text files in there, they will be useful.
- You may diff your previous Changelog with the one you just copied and read that diff.
-- You may enable `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in imconfig.h to forcefully disable legacy names and symbols.
- Doing it every once in a while is a good way to make sure you are not using obsolete symbols. Dear ImGui is in active development,
+- You may enable `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in imconfig.h to forcefully disable legacy names and symbols.
+ Doing it every once in a while is a good way to make sure you are not using obsolete symbols. Dear ImGui is in active development,
and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users.
- Please report any issue!
@@ -33,38 +33,153 @@ HOW TO UPDATE?
DOCKING BRANCH (In Progress)
-----------------------------------------------------------------------
+DOCKING FEATURES
+
- Added Docking system: [BETA] (#2109, #351)
- Added ImGuiConfigFlags_DockingEnable flag to enable Docking.
Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`.
- Added DockSpace() API.
- Added ImGuiDockNodeFlags flags for DockSpace().
- - Added SetNextWindowDock(), SetNextWindowDockFamily() API.
+ - Added SetNextWindowDock(), SetNextWindowClass() API.
- Added GetWindowDockId(), IsWindowDocked() API.
- Added ImGuiWindowFlags_NoDocking window flag to disable the possibility for a window to be docked.
Popup, Menu and Child windows always have the ImGuiWindowFlags_NoDocking flag set.
- Added io.ConfigDockingWithShift option to configure docking mode.
- Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingEmptyBg colors.
- Demo: Added "DockSpace" example app showcasing use of explicit dockspace nodes.
-- Added Tab Bar/Tabs widgets: (#261, #351)
- - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API.
- - Added ImGuiTabBarFlags flags for BeginTabBar().
- - Added ImGuiTabItemFlags flags for BeginTabItem().
- - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors.
- - Demo: Added Layout->Tabs demo code.
- - Demo: Added "Documents" example app showcasing possible use for tabs.
-- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering
- the ID, as a convenience to avoid using the ### operator.
+
+MULTI-VIEWPORT FEATURES (was previously 'viewport' branch, merged into 'docking')
+
+Breaking Changes:
+
+- IMPORTANT: When multi-viewports are enabled (with io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable),
+ all coordinates/positions will be in your natural OS coordinates space. It means that:
+ - Reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are _probably_ not what you want anymore.
+ Use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos).
+ - Likewise io.MousePos and GetMousePos() will use OS coordinates.
+ If you query mouse positions to interact with non-imgui coordinates you will need to offset them.
+ e.g. subtract GetWindowViewport()->Pos.
+- Render function: the ImDrawData structure now contains 'DisplayPos' and 'DisplaySize' fields.
+ To support multi-viewport, you need to use those values when creating your orthographic projection matrix.
+ Use 'draw_data->DisplaySize' instead of 'io.DisplaySize', and 'draw_data->DisplayPos' instead of (0,0) as the upper-left point.
+ You need to subtract 'draw_data->DisplayPos' from your scissor rectangles to convert them from global coordinates to frame-buffer coordinates.
+- IO: Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
+- IO: Removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were marked obsoleted, used to clip within the (0,0)..(DisplaySize) range).
+
+Other changes:
+(FIXME: This need a fuller explanation!)
+
+- Added ImGuiPlatformIO structure and GetPlatformIO().
+ Similarly to ImGuiIO and GetIO(), this structure is the main point of communication for back-ends supporting multi-viewports.
+- Added ImGuiPlatformMonitor to feed OS monitor information in the ImGuiPlatformIO::Monitors.
+- Added GetMainViewport().
+- Added GetWindowViewport(), SetNextWindowViewport().
+- Added GetWindowDpiScale().
+- Added GetOverlayDrawList(ImGuiViewport* viewport).
+ The no-parameter version of GetOverlayDrawList() return the overlay for the current window's viewport.
+- Added UpdatePlatformWindows(), RenderPlatformWindows(), DestroyPlatformWindows() for usage for application core.
+- Added FindViewportByID(), FindViewportByPlatformHandle() for usage by back-ends.
+- Added ImGuiConfigFlags_ViewportsEnable configuration flag and other viewport options.
+- Added ImGuiBackendFlags_PlatformHasViewports, ImGuiBackendFlags_RendererHasViewports, ImGuiBackendFlags_HasMouseHoveredViewport backend flags.
+- Added io.MainViewport, io.Viewports, io.MouseHoveredViewport (MouseHoveredViewport is optional _even_ for multi-viewport support).
+- Added ImGuiViewport structure, ImGuiViewportFlags flags.
+- Added ImGuiWindowClass and SetNextWindowClass() for passing viewport related hints to the OS/platform back-end.
+- Examples: Renderer: OpenGL2, OpenGL3, DirectX11, DirectX12, Vulkan: Added support for multi-viewports.
+- Examples: Platforms: Win32, GLFW, SDL2: Added support for multi-viewports.
+ Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117.
+- Examples: Win32: Added DPI-related helpers to access DPI features without requiring the latest Windows SDK at compile time,
+ and without requiring Windows 10 at runtime.
+- Examples: Vulkan: Added various optional helpers in imgui_impl_vulkan.h (they are used for multi-viewport support)
+ to make the examples main.cpp easier to read.
+
+
+-----------------------------------------------------------------------
+ VERSION 1.68 (In progress)
+-----------------------------------------------------------------------
+
+Other Changes:
+- Added .editorconfig file for text editors to standardize using spaces. (#2038) [@kudaba]
+- InputText: Fixed a bug where ESCAPE would not restore the initial value in all situations. (#2321) [@relick]
+- InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787)
+- Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value.
+- Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308)
+- Window: When resizing from an edge, the border is more visible and better follow the rounded corners.
+- ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle"
+ with a small number of segments (e.g. an hexagon). (#2287) [@baktery]
+- ImGuiTextBuffer: Added append() function (unformatted).
+- ImFontAtlas: Added 0x2000-0x206F general punctuation range to default ChineseFull/ChineseSimplifiedCommon ranges. (#2093)
+- ImFontAtlas: FreeType: Added support for imgui allocators + custom FreeType only SetAllocatorFunctions. (#2285) [@Vuhdo]
+- ImFontAtlas: FreeType: Fixed using imgui_freetype.cpp in unity builds. (#2302)
+- Demo: Fixed "Log" demo not initializing properly, leading to the first line not showing before a Clear. (#2318) [@bluescan]
+- Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created
+ in a different thread or parent. (#1951, #2087, #2156, #2232) [many people]
+- Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled).
+- Examples: Win32: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. (#2264)
+- Examples: DirectX9: Explicitly disable fog (D3DRS_FOGENABLE) before drawing in case user state has it set. (#2288, #2230)
-----------------------------------------------------------------------
- VERSION 1.67 (In Progress)
+ VERSION 1.67 (Released 2019-01-14)
-----------------------------------------------------------------------
Breaking Changes:
+- Made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable
+ side-effect because the window would have ID zero. In particular it is causing problems in viewport/docking branches.
+- Renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges and removed its [Beta] mark.
+ The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names.
+- Renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete).
+
Other Changes:
-- Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file
- to ease integration.
+
+- Added BETA api for Tab Bar/Tabs widgets: (#261, #351)
+ - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API.
+ - Added ImGuiTabBarFlags flags for BeginTabBar().
+ - Added ImGuiTabItemFlags flags for BeginTabItem().
+ - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors.
+ - Demo: Added Layout->Tabs demo code.
+ - Demo: Added "Documents" example app showcasing possible use for tabs.
+ This feature was merged from the Docking branch in order to allow the use of regular tabs in your code.
+ (It does not provide the docking/splitting/merging of windows available in the Docking branch)
+- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, as a convenience
+ to avoid using the ### operator. In the Docking branch this also has an effect on tab closing behavior.
+- Window, Focus, Popup: Fixed an issue where closing a popup by clicking another window with the _NoMove flag would refocus
+ the parent window of the popup instead of the newly clicked window.
+- Window: Contents size is preserved while a window collapsed. Fix auto-resizing window losing their size for one frame when uncollapsed.
+- Window: Contents size is preserved while a window contents is hidden (unless it is hidden for resizing purpose).
+- Window: Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that
+ it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-ends do.
+- Window: Added io.ConfigWindowsMoveFromTitleBarOnly option. This is ignored by window with no title bars (often popups).
+ This affects clamping window within the visible area: with this option enabled title bars need to be visible. (#899)
+- Window: Fixed using SetNextWindowPos() on a child window (which wasn't really documented) position the cursor as expected
+ in the parent window, so there is no mismatch between the layout in parent and the position of the child window.
+- InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257)
+- DragFloat: Fixed broken mouse direction change with power!=1.0. (#2174, #2206) [@Joshhua5]
+- Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary
+ keep the focus on the parent window, which could steal it from newly appearing windows. (#787)
+- Nav: Fixed animated window titles from being updated when displayed in the CTRL+Tab list. (#787)
+- Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function closer
+ to the user call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651)
+ Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen.
+ Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected
+ into e.g. an error log and stopping the script execution.
+- ImFontAtlas: Stb and FreeType: Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth).
+- ImFontAtlas: Stb and FreeType: Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233)
+- ImFontAtlas: Stb and FreeType: Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas.
+- ImFontAtlas: FreeType: Fixed abnormally high atlas height.
+- ImFontAtlas: FreeType: Fixed support for any values of TexGlyphPadding (not just only 1).
+- ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible.
+ (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.)
+- IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends.
+- IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
+- IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful
+ for automation to not have an upper limit on typing speed. Will later transition key/mouse to use the event queue later.
+- Style: Tweaked default value of style.DisplayWindowPadding from (20,20) to (19,19) so the default style as a value
+ which is the same as the title bar height.
+- Demo: "Simple Layout" and "Style Editor" are now using tabs.
+- Demo: Added a few more things under "Child windows" (changing ImGuiCol_ChildBg, positioning child, using IsItemHovered after a child).
+- Examples: DirectX10/11/12: Made imgui_impl_dx10/dx11/dx12.cpp link d3dcompiler.lib from the .cpp file to ease integration.
+- Examples: Allegro 5: Properly destroy globals on shutdown to allow for restart. (#2262) [@DomRe]
-----------------------------------------------------------------------
@@ -76,7 +191,7 @@ Other Changes:
- Fixed a text rendering/clipping bug introduced in 1.66 (on 2018-10-12, commit ede3a3b9) that affect single ImDrawList::AddText()
calls with single strings larger than 10k. Text/TextUnformatted() calls were not affected, but e.g. InputText() was. [@pdoane]
- When the focused window become inactive don't restore focus to a window with the ImGuiWindowFlags_NoInputs flag. (#2213) [@zzzyap]
-- Separator: Fixed Separator() outputting an extraneous empty line when captured into clipboard/text/file.
+- Separator: Fixed Separator() outputting an extraneous empty line when captured into clipboard/text/file.
- Demo: Added ShowAboutWindow() call, previously was only accessible from the demo window.
- Demo: ShowAboutWindow() now display various Build/Config Information (compiler, os, etc.) that can easily be copied into bug reports.
- Fixed build issue with osxcross and macOS. (#2218) [@dos1]
@@ -95,7 +210,7 @@ Breaking Changes:
Other Changes:
-- Fixed calling SetNextWindowSize()/SetWindowSize() with non-integer values leading to
+- Fixed calling SetNextWindowSize()/SetWindowSize() with non-integer values leading to
accidental alteration of window position. We now round the provided size. (#2067)
- Fixed calling DestroyContext() always saving .ini data with the current context instead
of the supplied context pointer. (#2066)
@@ -104,7 +219,7 @@ Other Changes:
- Nav: Fixed an assert in certain circumstance (mostly when using popups) when mouse positions stop being valid. (#2168)
- Nav: Fixed explicit directional input not re-highlighting current nav item if there is a single item in the window
and highlight has been previously disabled by the mouse. (#787)
-- DragFloat: Fixed a situation where dragging with value rounding enabled or with a power curve
+- DragFloat: Fixed a situation where dragging with value rounding enabled or with a power curve
erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075).
- DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024)
- DragFloat: Disabled setting a default drag speed when one edge is FLT_MAX. (#2024)
@@ -123,9 +238,9 @@ Other Changes:
to the provided string to uniquely identify the child window. This was undoing an intentional change
introduced in 1.50 and broken in 1.60. (#1698, #894, #713).
- TextUnformatted(): Fixed a case where large-text path would read bytes past the text_end marker depending
- on the position of new lines in the buffer (it wasn't affecting the output but still not the right thing to do!)
-- ListBox(): Fixed frame sizing when items_count==1 unnecessarily showing a scrollbar. (#2173) [@luk1337, @ocornut]
-- ListBox(): Tweaked frame sizing so list boxes will look more consistent when FramePadding is far from ItemSpacing.
+ on the position of new lines in the buffer (it wasn't affecting the output but still not the right thing to do!)
+- ListBox(): Fixed frame sizing when items_count==1 unnecessarily showing a scrollbar. (#2173) [@luk1337, @ocornut]
+- ListBox(): Tweaked frame sizing so list boxes will look more consistent when FramePadding is far from ItemSpacing.
- RenderText(): Some optimization for very large text buffers, useful for non-optimized builds.
- BeginMenu(): Fixed menu popup horizontal offset being off the item in the menu bar when WindowPadding=0.0f.
- ArrowButton(): Fixed arrow shape being horizontally misaligned by (FramePadding.y-FramePadding.x) if they are different.
@@ -183,7 +298,7 @@ Changes:
isolate your patches. You can peak at imgui_widgets.cpp from 1.64 to get a sense of what is included in it,
then separate your changes into several patches that can more easily be applied to 1.64 on a per-file basis.
What I found worked nicely for me, was to open the diff of the old patches in an interactive merge/diff tool,
- search for the corresponding function in the new code and apply the chunks manually.
+ search for the corresponding function in the new code and apply the chunks manually.
- As a reminder, if you have any change to imgui.cpp it is a good habit to discuss them on the github,
so a solution applicable on the Master branch can be found. If your company has changes that you cannot
disclose you may also contact me privately.
@@ -199,10 +314,10 @@ Breaking Changes:
- Changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecision over time.
- Removed per-window ImGuiWindowFlags_ResizeFromAnySide Beta flag in favor `io.ConfigResizeWindowsFromEdges=true` to enable the feature globally. (#1495)
The feature is not currently enabled by default because it is not satisfying enough, but will eventually be.
-- InputText: Renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency.
- Kept redirection types (will obsolete).
+- InputText: Renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency.
+ Kept redirection types (will obsolete).
- InputText: Removed ImGuiTextEditCallbackData::ReadOnly since it is a duplication of (ImGuiTextEditCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
-- Renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API.
+- Renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API.
Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).
- Renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to io.ConfigMacOSXBehaviors for consistency. (#1427, #473)
- Removed obsolete redirection functions: CollapsingHeader() variation with 2 bools - marked obsolete in v1.49, May 2016.
@@ -216,17 +331,17 @@ Other Changes:
While it was previously possible, you won't be able to CTRL-TAB out and immediately back in a window with the ImGuiWindow_NoNavFocus flag.
- Window: Allow menu and popups windows from ignoring the style.WindowMinSize values so short menus/popups are not padded. (#1909)
- Window: Added global io.ConfigResizeWindowsFromEdges option to enable resizing windows from their edges and from the lower-left corner. (#1495)
-- Window: Collapse button shows hovering highlight + clicking and dragging on it allows to drag the window as well.
+- Window: Collapse button shows hovering highlight + clicking and dragging on it allows to drag the window as well.
- Added IsItemEdited() to query if the last item modified its value (or was pressed). This is equivalent to the bool returned by most widgets.
It is useful in some situation e.g. using InputText() with ImGuiInputTextFlags_EnterReturnsTrue. (#2034)
- InputText: Added support for buffer size/capacity changes via the ImGuiInputTextFlags_CallbackResize flag. (#2006, #1443, #1008).
- InputText: Fixed not tracking the cursor horizontally when modifying the text buffer through a callback.
- InputText: Fixed minor off-by-one issue when submitting a buffer size smaller than the initial zero-terminated buffer contents.
-- InputText: Fixed a few pathological crash cases on single-line InputText widget with multiple millions characters worth of contents.
+- InputText: Fixed a few pathological crash cases on single-line InputText widget with multiple millions characters worth of contents.
Because the current text drawing function reserve for a worst-case amount of vertices and how we handle horizontal clipping,
- we currently just avoid displaying those single-line widgets when they are over a threshold of 2 millions characters,
+ we currently just avoid displaying those single-line widgets when they are over a threshold of 2 millions characters,
until a better solution is found.
-- Drag and Drop: Fixed an incorrect assert when dropping a source that is submitted after the target (bug introduced with 1.62 changes
+- Drag and Drop: Fixed an incorrect assert when dropping a source that is submitted after the target (bug introduced with 1.62 changes
related to the addition of IsItemDeactivated()). (#1875, #143)
- Drag and Drop: Fixed ImGuiDragDropFlags_SourceNoDisableHover to affect hovering state prior to calling IsItemHovered() + fixed description. (#143)
- Drag and Drop: Calling BeginTooltip() between a BeginDragSource()/EndDragSource() or BeginDropTarget()/EndDropTarget() uses adjusted tooltip
@@ -239,11 +354,11 @@ Other Changes:
- Misc: Added optional misc/stl/imgui_stl.h wrapper to use with STL types (e.g. InputText with std::string). (#2006, #1443, #1008)
[*EDIT* renamed to misc/std/imgui_stdlib.h in 1.66]
- Misc: Added IMGUI_VERSION_NUM for easy compile-time testing. (#2025)
-- Misc: Added ImGuiMouseCursor_Hand cursor enum + corresponding software cursor. (#1913, 1914) [@aiekick, @ocornut]
+- Misc: Added ImGuiMouseCursor_Hand cursor enum + corresponding software cursor. (#1913, 1914) [@aiekick, @ocornut]
- Misc: Tweaked software mouse cursor offset to match the offset of the corresponding Windows 10 cursors.
- Made assertion more clear when trying to call Begin() outside of the NewFrame()..EndFrame() scope. (#1987)
- Fixed assertion when transitioning from an active ID to another within a group, affecting ColorPicker (broken in 1.62). (#2023, #820, #956, #1875).
-- Fixed PushID() from keeping alive the new ID Stack top value (if a previously active widget shared the ID it would be erroneously kept alive).
+- Fixed PushID() from keeping alive the new ID Stack top value (if a previously active widget shared the ID it would be erroneously kept alive).
- Fixed horizontal mouse wheel not forwarding the request to the parent window if ImGuiWindowFlags_NoScrollWithMouse is set. (#1463, #1380, #1502)
- Fixed a include build issue for Cygwin in non-POSIX (Win32) mode. (#1917, #1319, #276)
- ImDrawList: Improved handling for worst-case vertices reservation policy when large amount of text (e.g. 1+ million character strings)
@@ -262,15 +377,15 @@ Other Changes:
- Examples: OSX: Added early raw OSX platform backend. (#1873) [@pagghiu, @itamago, @ocornut]
- Examples: Added mac OSX & iOS + Metal example in example_apple_metal/. (#1929, #1873) [@warrenm]
- Examples: Added mac OSX + OpenGL2 example in example_apple_opengl2/. (#1873)
-- Examples: OpenGL3: Added shaders more versions of GLSL. (#1938, #1941, #1900, #1513, #1466, etc.)
-- Examples: OpenGL3: Tweaked the imgui_impl_opengl3.cpp to work as-is with Emscripten + WebGL 2.0. (#1941). [@o-micron]
+- Examples: OpenGL3: Added shaders more versions of GLSL. (#1938, #1941, #1900, #1513, #1466, etc.)
+- Examples: OpenGL3: Tweaked the imgui_impl_opengl3.cpp to work as-is with Emscripten + WebGL 2.0. (#1941). [@o-micron]
- Examples: OpenGL3: Made the example app default to GL 3.0 + GLSL 130 (instead of GL 3.2 + GLSL 150) unless on Mac.
- Examples: OpenGL3: Added error output when shaders fail to compile/link.
- Examples: OpenGL3: Added support for glew and glad OpenGL loaders out of the box. (#2001, #2002) [@jdumas]
- Examples: OpenGL2: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications. (#1996)
- Examples: DirectX10, DirectX11: Fixed unreleased resources in Init and Shutdown functions. (#1944)
- Examples: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility. (#1989) [@matt77hias]
-- Examples: Vulkan: Fixed handling of VkSurfaceCapabilitiesKHR::maxImageCount = 0 case. Tweaked present mode selections.
+- Examples: Vulkan: Fixed handling of VkSurfaceCapabilitiesKHR::maxImageCount = 0 case. Tweaked present mode selections.
- Examples: Win32, Glfw, SDL: Added support for the ImGuiMouseCursor_Hand cursor.
@@ -280,8 +395,8 @@ Other Changes:
Breaking Changes:
-- TreeNodeEx(): The helper ImGuiTreeNodeFlags_CollapsingHeader flag now include ImGuiTreeNodeFlags_NoTreePushOnOpen. The flag was already set by CollapsingHeader().
- The only difference is if you were using TreeNodeEx() manually with ImGuiTreeNodeFlags_CollapsingHeader and without ImGuiTreeNodeFlags_NoTreePushOnOpen.
+- TreeNodeEx(): The helper ImGuiTreeNodeFlags_CollapsingHeader flag now include ImGuiTreeNodeFlags_NoTreePushOnOpen. The flag was already set by CollapsingHeader().
+ The only difference is if you were using TreeNodeEx() manually with ImGuiTreeNodeFlags_CollapsingHeader and without ImGuiTreeNodeFlags_NoTreePushOnOpen.
In this case you can remove the ImGuiTreeNodeFlags_NoTreePushOnOpen flag from your call (ImGuiTreeNodeFlags_CollapsingHeader & ~ImGuiTreeNodeFlags_NoTreePushOnOpen). (#1864)
This also apply if you were using internal's TreeNodeBehavior() with the ImGuiTreeNodeFlags_CollapsingHeader flag directly.
- ImFontAtlas: Renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish new smaller variants and discourage using the full set. (#1859)
@@ -298,23 +413,23 @@ Other Changes:
before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl2.cpp
before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp etc.
- The idea is what we can now easily combine and maintain back-ends and reduce code redundancy. Individual files are smaller and more reusable.
- Integration of imgui into a new/custom engine may also be easier as there is less overlap between "windowing / inputs" and "rendering" code,
+ Integration of imgui into a new/custom engine may also be easier as there is less overlap between "windowing / inputs" and "rendering" code,
so you may study or grab one half of the code and not the other.
- - This change was motivated by the fact that adding support for the upcoming multi-viewport feature requires more work from the Platform and Renderer
- back-ends, and the amount of redundancy across files was becoming too difficult to maintain. If you use default back-ends, you'll benefit from an
+ - This change was motivated by the fact that adding support for the upcoming multi-viewport feature requires more work from the Platform and Renderer
+ back-ends, and the amount of redundancy across files was becoming too difficult to maintain. If you use default back-ends, you'll benefit from an
easy update path to support multi-viewports later (for future ImGui 1.7x).
- - This is not strictly a breaking change if you keep your old bindings, but when you'll want to fully update your bindings,
- expect to have to reshuffle a few things.
+ - This is not strictly a breaking change if you keep your old bindings, but when you'll want to fully update your bindings,
+ expect to have to reshuffle a few things.
- Each example still has its own main.cpp which you may refer you to understand how to initialize and glue everything together.
- Some frameworks (such as the Allegro, Marmalade) handle both the "platform" and "rendering" part, and your custom engine may as well.
- Read examples/README.txt for details.
- Added IsItemDeactivated() to query if the last item was active previously and isn't anymore. Useful for Undo/Redo patterns. (#820, #956, #1875)
-- Added IsItemDeactivatedAfterChange() [*EDIT* renamed to IsItemDeactivatedAfterEdit() in 1.63] if the last item was active previously,
- is not anymore, and during its active state modified a value. Note that you may still get false positive (e.g. drag value and while
+- Added IsItemDeactivatedAfterChange() [*EDIT* renamed to IsItemDeactivatedAfterEdit() in 1.63] if the last item was active previously,
+ is not anymore, and during its active state modified a value. Note that you may still get false positive (e.g. drag value and while
holding return on the same value). (#820, #956, #1875)
- Nav: Added support for PageUp/PageDown (explorer-style: first aim at bottom/top most item, when scroll a page worth of contents). (#787)
- Nav: To keep the navigated item in view we also attempt to scroll the parent window as well as the current window. (#787)
-- ColorEdit3, ColorEdit4, ColorButton: Added ImGuiColorEditFlags_NoDragDrop flag to disable ColorEditX as drag target and ColorButton as drag source. (#1826)
+- ColorEdit3, ColorEdit4, ColorButton: Added ImGuiColorEditFlags_NoDragDrop flag to disable ColorEditX as drag target and ColorButton as drag source. (#1826)
- BeginDragDropSource(): Offset tooltip position so it is off the mouse cursor, but also closer to it than regular tooltips, and not clamped by viewport. (#1739)
- BeginDragDropTarget(): Added ImGuiDragDropFlags_AcceptNoPreviewTooltip flag to request hiding the drag source tooltip from the target site. (#143)
- BeginCombo(), BeginMainMenuBar(), BeginChildFrame(): Temporary style modification are restored at the end of BeginXXX instead of EndXXX, to not affect tooltips and child windows.
@@ -326,15 +441,15 @@ Other Changes:
- ImFontAtlas: Added GetGlyphRangesChineseSimplifiedCommon() helper that returns a list of ~2500 most common Simplified Chinese characters. (#1859) [@JX-Master, @ocornut]
- Examples: OSX: Added imgui_impl_osx.mm binding to be used along with e.g. imgui_impl_opengl2.cpp. (#281, #1870) [@pagghiu, @itamago, @ocornut]
- Examples: GLFW: Made it possible to Shutdown/Init the backend again (by reseting the time storage properly). (#1827) [@ice1000]
-- Examples: Win32: Fixed handling of mouse wheel messages to support sub-unit scrolling messages (typically sent by track-pads). (#1874) [@zx64]
+- Examples: Win32: Fixed handling of mouse wheel messages to support sub-unit scrolling messages (typically sent by track-pads). (#1874) [@zx64]
- Examples: SDL+Vulkan: Added SDL+Vulkan example.
-- Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. Added clipboard support.
+- Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. Added clipboard support.
- Examples: Allegro5: Unindexing buffers ourselves as Allegro indexed drawing primitives are buggy in the DirectX9 back-end (will be fixed in Allegro 5.2.5+).
- Examples: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from ImGui_ImplDX12_NewFrame() to ImGui_ImplDX12_RenderDrawData() which makes a lots more sense. (#301)
-- Examples: Vulkan: Reordered parameters ImGui_ImplVulkan_RenderDrawData() to be consistent with other bindings, a good occasion since we refactored the code.
+- Examples: Vulkan: Reordered parameters ImGui_ImplVulkan_RenderDrawData() to be consistent with other bindings, a good occasion since we refactored the code.
- Examples: FreeGLUT: Added FreeGLUT bindings. Added FreeGLUT+OpenGL2 example. (#801)
- Examples: The functions in imgui_impl_xxx.cpp are prefixed with IMGUI_IMPL_API (which defaults to IMGUI_API) to facilitate some uses. (#1888)
-- Examples: Fixed bindings to use ImGuiMouseCursor_COUNT instead of old name ImGuiMouseCursor_Count_ so they can compile with IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#1887)
+- Examples: Fixed bindings to use ImGuiMouseCursor_COUNT instead of old name ImGuiMouseCursor_Count_ so they can compile with IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#1887)
- Misc: Updated stb_textedit from 1.09 + patches to 1.12 + minor patches.
- Internals: PushItemFlag() flags are inherited by BeginChild().
@@ -408,37 +523,6 @@ The gamepad/keyboard navigation branch (which has been in the work since July 20
Gamepad/keyboard navigation is still marked as Beta and has to be enabled explicitly.
Various internal refactoring have also been done, as part of the navigation work and as part of the upcoming viewport/docking work.
-VIEWPORT BRANCH
-(IN PROGRESS, WILL MERGE INTO THE MAIN LISTS WHEN WE MERGE THE BRANCH)
-
- - Viewport: Added support for multi-viewport [...] blah blah
- - Viewport: Rendering: the ImDrawData structure now contains 'DisplayPos' and 'DisplaySize' fields. To support multi-viewport, you need to use those values when
- creating your orthographic projection matrix. Use 'draw_data->DisplaySize' instead of 'io.DisplaySize', and 'draw_data->DisplayPos' instead of (0,0) as the upper-left point.
- You also need to subtract 'draw_data->DisplayPos' from your scissor rectangles, as scissor rectangles are specified in the space of your target viewport.
- - Examples: Back-ends have been refactored to separate the platform code (e.g. Win32, Glfw, SDL2) from the renderer code (e.g. DirectX11, OpenGL3, Vulkan).
- before: imgui_impl_dx11.cpp --> after: imgui_impl_win32.cpp + imgui_impl_dx11.cpp
- before: imgui_impl_dx12.cpp --> after: imgui_impl_win32.cpp + imgui_impl_dx12.cpp
- before: imgui_impl_glfw_gl3.cpp --> after: imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp
- before: imgui_impl_glfw_vulkan.cpp --> after: imgui_impl_glfw.cpp + imgui_impl_vulkan.cpp
- before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl2.cpp
- before: imgui_impl_sdl_gl3.cpp --> after: imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp
- etc.
- - The idea is what we can now easily combine and maintain back-ends and reduce code redundancy. Integration of imgui into a new/custom engine may also
- be easier as there is less overlap between "windowing / inputs" and "rendering" code, so you may study or grab one half of the code and not the other.
- - This change was motivated by the fact that adding support for multi-viewport requires more work from the platform and renderer back-ends, and the
- amount of redundancy accross files was becoming too difficult to maintain.
- - Some frameworks (such as the Allegro, Marmalade) handle both the "platform" and "rendering" part, and your custom engine may as well.
- - Each example still has its own main.cpp which you may refer you to understand how to initialize and glue everything together.
- - Examples: Win32: Added DPI-related helpers to access DPI features _without_ requiring the latest Windows SDK at compile time, and _without_ requiring Windows 10 at runtime.
- - Examples: Platforms currently supporting multi-viewport: Win32, Glfw, SDL2.
- - Examples: Renderers currently supporting multi-viewport: DirectX10, DirectX11, OpenGL2, OpenGL3, Vulkan (WIP).
- - Examples: All imgui_impl_xxx files now have an individual Changelog at the top of the file, making it easier to follow how back-ends are evolving.
- - Examples: Vulkan: Added various optional helpers in imgui_impl_vulkan.h (they are used for multi-viewport support) to make the examples main.cpp easier to read.
- - Examples: Allegro: Renamed imgui_impl_a5.xxx files to imgui_impl_allegro5.xxx, ImGui_ImplA5_** symbols to ImGui_ImplAllegro5_xxx.
- - Examples: Vulkan+SDL: Added a Vulkan+SDL example. (#1367) [@gmueckl]
- - Metrics: Added a "Show window begin order" checkbox to visualize the order windows are submitted.
- - Internal: Settings: Added ReadCloseFn handler to be able to patch/alter a loaded object after all the fields are known.
-
Breaking Changes:
- Obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render().
@@ -461,7 +545,7 @@ Breaking Changes:
- Renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
- Removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it should be easy to replicate on your side (you can find the code in 1.53).
- [EDITED] Window: BeginChild() with an explicit name doesn't include the hash within the internal window name. (#1698)
- This change was erroneously introduced, undoing the change done for #894, #713, and not documented properly in the original
+ This change was erroneously introduced, undoing the change done for #894, #713, and not documented properly in the original
1.60 release Changelog. It was fixed on 2018-09-28 (1.66) and I wrote this paragraph the same day.
Other Changes:
@@ -475,7 +559,7 @@ Other Changes:
- See https://github.com/ocornut/imgui/issues/1599 for recommended gamepad mapping or download PNG/PSD at http://goo.gl/9LgVZW
- See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. Read imgui.cpp for more details.
- To use Keyboard Navigation:
- - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
+ - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
- Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, Escape to cancel/close, Ctrl-Tab to focus windows, etc.
- When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set.
For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details.
@@ -750,6 +834,7 @@ Breaking Changes:
- Removed `IsItemRectHovered()`, `IsWindowRectHovered()` recently introduced in 1.51 which were merely the more consistent/correct names for the above functions which are now obsolete anyway. (#1382)
- Changed `IsWindowHovered()` default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. (#1382)
- Renamed imconfig.h's `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS` to `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` for consistency.
+- Renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete).
Other Changes:
diff --git a/docs/README.md b/docs/README.md
index bd711799..a6c4b416 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,23 +1,26 @@
-dear imgui,
+dear imgui
=====
[![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui)
[![Coverity Status](https://scan.coverity.com/projects/4720/badge.svg)](https://scan.coverity.com/projects/4720)
-_(This library is free but needs your support to sustain its development. There are many desirable features and maintenance ahead. If you are an individual using dear imgui, please consider donating via Patreon or PayPal. If your company is using dear imgui, please consider financial support (e.g. sponsoring a few weeks/months of development). I can invoice for technical support, custom development etc. Email: omarcornut at gmail)._
+_(This library is free as in freedom, but needs your support to sustain its development. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for invoiced financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal.)_
-Monthly donations via Patreon:
-
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui)
+Individuals/hobbyists: support continued maintenance and development via the monthly Patreon:
+
[![Patreon](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/patreon_01.png)](http://www.patreon.com/imgui)
-One-off donations via PayPal:
-
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U)
+Individuals/hobbyists: support continued maintenance and development via PayPal:
+
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S)
+
+Businesses: support continued maintenance and development via support contracts or sponsoring:
+
_E-mail: omarcornut at gmail dot com_
Dear ImGui is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies).
Dear ImGui is designed to enable fast iterations and to empower programmers to create content creation tools and visualization / debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and lacks certain features normally found in more high-level libraries.
-Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard.
+Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard.
-See [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui), [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Gallery](https://github.com/ocornut/imgui/issues/1902) pages to get an idea of its use cases.
+See [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui), [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Gallery](https://github.com/ocornut/imgui/issues/2265) pages to get an idea of its use cases.
Dear ImGui is self-contained within a few files that you can easily copy and compile into your application/engine:
- imgui.cpp
@@ -73,7 +76,7 @@ ImGui::ColorEdit4("Color", my_color);
// Plot some values
const float my_values[] = { 0.2f, 0.1f, 1.0f, 0.5f, 0.9f, 2.2f };
ImGui::PlotLines("Frame Times", my_values, IM_ARRAYSIZE(my_values));
-
+
// Display contents in a scrolling region
ImGui::TextColored(ImVec4(1,1,0,1), "Important Stuff");
ImGui::BeginChild("Scrolling");
@@ -87,13 +90,13 @@ Result:
### How it works
-Check out the References section if you want to understand the core principles behind the IMGUI paradigm. An IMGUI tries to minimize superfluous state duplication, state synchronization and state retention from the user's point of view. It is less error prone (less code and less bugs) than traditional retained-mode interfaces, and lends itself to create dynamic user interfaces.
+Check out the References section if you want to understand the core principles behind the IMGUI paradigm. An IMGUI tries to minimize superfluous state duplication, state synchronization and state retention from the user's point of view. It is less error prone (less code and less bugs) than traditional retained-mode interfaces, and lends itself to create dynamic user interfaces.
-Dear ImGui outputs vertex buffers and command lists that you can easily render in your application. The number of draw calls and state changes required to render them is fairly small. Because Dear ImGui doesn't know or touch graphics state directly, you can call its functions anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate dear imgui with your existing codebase.
+Dear ImGui outputs vertex buffers and command lists that you can easily render in your application. The number of draw calls and state changes required to render them is fairly small. Because Dear ImGui doesn't know or touch graphics state directly, you can call its functions anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate dear imgui with your existing codebase.
_A common misunderstanding is to mistake immediate mode gui for immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes as the gui functions are called. This is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are decently optimal and you can render them later, in your app or even remotely._
-Dear ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue (hot code reload) feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! Dear ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, an entire game making editor/framework, etc.
+Dear ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue (hot code reload) feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! Dear ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, an entire game making editor/framework, etc.
Demo Binaries
-------------
@@ -123,8 +126,9 @@ Languages: (third-party bindings)
- Odin: [odin-dear_imgui](https://github.com/ThisDrunkDane/odin-dear_imgui)
- Pascal: [imgui-pas](https://github.com/dpethes/imgui-pas)
- PureBasic: [pb-cimgui](https://github.com/hippyau/pb-cimgui)
-- Python [CyImGui](https://github.com/chromy/cyimgui) or [pyimgui](https://github.com/swistakm/pyimgui)
-- Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs)
+- Python: [pyimgui](https://github.com/swistakm/pyimgui) or [bimpy](https://github.com/podgorskiy/bimpy)
+- Ruby: [ruby-imgui](https://github.com/vaiorabbit/ruby-imgui)
+- Rust: [imgui-rs](https://github.com/Gekkio/imgui-rs) or [imgui-rust](https://github.com/nsf/imgui-rust)
- Swift [swift-imgui](https://github.com/mnmly/Swift-imgui)
Frameworks:
@@ -143,9 +147,9 @@ Frameworks:
- OpenSceneGraph/OSG: [gist](https://gist.github.com/fulezi/d2442ca7626bf270226014501357042c)
- ORX: [pr #1843](https://github.com/ocornut/imgui/pull/1843)
- LÖVE+Lua: [love-imgui](https://github.com/slages/love-imgui)
-- Magnum: [magnum-imgui](https://github.com/lecopivo/magnum-imgui), [MagnumImguiPort](https://github.com/lecopivo/MagnumImguiPort)
+- Magnum: [ImGuiIntegration](https://doc.magnum.graphics/magnum/namespaceMagnum_1_1ImGuiIntegration.html) ([example](https://doc.magnum.graphics/magnum/examples-imgui.html))
- NanoRT: [syoyo/imgui](https://github.com/syoyo/imgui/tree/nanort)
-- Qt3d: [imgui-qt3d](https://github.com/alpqr/imgui-qt3d), QOpenGLWindow [qtimgui](https://github.com/ocornut/imgui/issues/1910)
+- Qt: [imgui-qt3d](https://github.com/alpqr/imgui-qt3d) / [QOpenGLWindow (qtimgui)](https://github.com/ocornut/imgui/issues/1910) / [QtDirect3D](https://github.com/giladreich/QtDirect3D) / [qt6](https://github.com/alpqr/qvk6/tree/imgui/examples/rhi/imguidemo)
- SFML: [imgui-sfml](https://github.com/EliasD/imgui-sfml)
- Software renderer: [imgui_software_renderer](https://github.com/emilk/imgui_software_renderer)
- Unreal Engine 4: [segross/UnrealImGui](https://github.com/segross/UnrealImGui) or [sronsse/UnrealEngine_ImGui](https://github.com/sronsse/UnrealEngine_ImGui)
@@ -158,7 +162,7 @@ Some of the goals for 2019 are:
- Finish work on docking, tabs. (see [#2109](https://github.com/ocornut/imgui/issues/2109), public branch looking for feedback)
- Finish work on multiple viewports / multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), public branch looking for feedback)
- Finish work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787))
-- Add an automation and testing system, both to test the library and end-user apps.
+- Add an automation and testing system, both to test the library and end-user apps. (see [#435](https://github.com/ocornut/imgui/issues/435))
- Make Columns better. (they are currently pretty terrible!)
- Make the examples look better, improve styles, improve font support, make the examples hi-DPI aware.
@@ -171,41 +175,26 @@ User screenshots:
[Gallery Part 4](https://github.com/ocornut/imgui/issues/973) (Jan 2017 to Aug 2017)
[Gallery Part 5](https://github.com/ocornut/imgui/issues/1269) (Aug 2017 to Feb 2018)
[Gallery Part 6](https://github.com/ocornut/imgui/issues/1607) (Feb 2018 to June 2018)
-
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 onward)
+
[Gallery Part 7](https://github.com/ocornut/imgui/issues/1902) (June 2018 to January 2019)
+
[Gallery Part 8](https://github.com/ocornut/imgui/issues/2265) (January 2019 onward)
Also see the [Mega screenshots](https://github.com/ocornut/imgui/issues/1273) for an idea of the available features.
-Various tools
+Custom engine
[![screenshot game](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v149/gallery_TheDragonsTrap-01-thumb.jpg)](https://cloud.githubusercontent.com/assets/8225057/20628927/33e14cac-b329-11e6-80f6-9524e93b048a.png)
+Custom engine
[![screenshot tool](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/editor_white_preview.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/editor_white.png)
-![screenshot demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/v160-misc-classic.png)
+Demo window
+![screenshot demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png)
-[![screenshot profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler-880.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler.png)
-
-Dear ImGui can load TTF/OTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with:
-Code:
-```cpp
-ImGuiIO& io = ImGui::GetIO();
-io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
-```
-```cpp
-ImGui::Text(u8"こんにちは!テスト %d", 123);
-if (ImGui::Button(u8"ロード"))
-{
- // do stuff
-}
-ImGui::InputText("string", buf, IM_ARRAYSIZE(buf));
-ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
-```
-Result:
-
![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/code_sample_02_jp.png)
-
_(settings: Dark style (left), Light style (right) / Font: NotoSansCJKjp-Medium, 20px / Rounding: 5)_
+[Tracy Profiler](https://bitbucket.org/wolfpld/tracy)
+![tracy profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/tracy_profiler.png)
References
----------
-The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works.
+The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works.
- [Johannes 'johno' Norneby's article](http://www.johno.se/book/imgui.html).
- [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf).
- [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/).
@@ -218,7 +207,7 @@ See the [Wiki](https://github.com/ocornut/imgui/wiki) for more references and [B
Support Forums
--------------
-If you have issues with: compiling, linking, adding fonts, running or displaying Dear ImGui, or wiring inputs: please post on the Discourse forum: https://discourse.dearimgui.org.
+If you have issues with: compiling, linking, adding fonts, running or displaying Dear ImGui, or wiring inputs: please post on the Discourse forums: https://discourse.dearimgui.org.
For any other questions, bug reports, requests, feedback, you may post on https://github.com/ocornut/imgui/issues. Please read and fill the New Issue template carefully.
@@ -227,15 +216,15 @@ Frequently Asked Question (FAQ)
**Where is the documentation?**
-- The documentation is at the top of imgui.cpp + effectively imgui.h.
-- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
-- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
+- The documentation is at the top of imgui.cpp + effectively imgui.h.
+- Example code is in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output.
+- Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder.
- We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort.
-- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
+- Your programming IDE is your friend, find the type or function declaration to find comments associated to it.
**Which version should I get?**
-I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
+I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported.
You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) branches. Even though they are marked beta, several projects are using them and they are kept in sync with master regularly.
@@ -243,33 +232,27 @@ You may also peak at the [Multi-Viewport](https://github.com/ocornut/imgui/issue
See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) and [Software using dear imgui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) pages for an (incomplete) list of games/software which are publicly known to use dear imgui. Please add yours if you can!
-**Why the odd dual naming, "dear imgui" vs "ImGui"?**
+**Why the odd dual naming, "Dear ImGui" vs "ImGui"?**
The library started its life and is best known as "ImGui" only due to the fact that I didn't give it a proper name when I released it. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations. It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "dear imgui" that people can use to refer to this specific library in ambiguous situations.
**How can I tell whether to dispatch mouse/keyboard to imgui or to my application?**
**How can I display an image? What is ImTextureID, how does it works?**
-
**How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack.**
+
**How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.**
**How can I use my own math types instead of ImVec2/ImVec4?**
**How can I load a different font than the default?**
**How can I easily use icons in my application?**
**How can I load multiple fonts?**
-
**How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?**
+
**How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?** ([example](https://github.com/ocornut/imgui/wiki/Loading-Font-Example))
+
**How can I interact with standard C++ types (such as std::string and std::vector)?**
**How can I use the drawing facilities without an Dear ImGui window? (using ImDrawList API)**
+
**How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)**
**I integrated Dear ImGui in my engine and the text or lines are blurry..**
**I integrated Dear ImGui in my engine and some elements are disappearing when I move windows around..**
**How can I help?**
See the FAQ in imgui.cpp for answers.
-**How do you use Dear ImGui on a platform that may not have a mouse or keyboard?**
-
-You can control Dear ImGui with a gamepad, see the explanation in imgui.cpp about how to use the navigation feature (short version: map your gamepad inputs into the `io.NavInputs[]` array and set `io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad`).
-
-You can share your computer mouse seamlessly with your console/tablet/phone using [Synergy](http://synergy-project.org). This is the preferred solution for developer productivity. In particular, their [micro-synergy-client](https://github.com/symless/micro-synergy-client) repo there is _uSynergy.c_ sources for a small embeddable that you can use on any platform to connect to your host PC using Synergy 1.x. You may also use a third party solution such as [Remote ImGui](https://github.com/JordiRos/remoteimgui).
-
-For touch inputs, you can increase the hit box of widgets (via the _style.TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing for screen real-estate and precision.
-
**Can you create elaborate/serious tools with Dear ImGui?**
Yes. People have written game editors, data browsers, debuggers, profilers and all sort of non-trivial tools with the library. In my experience the simplicity of the API is very empowering. Your UI runs close to your live data. Make the tools always-on and everybody in the team will be inclined to create new tools (as opposed to more "offline" UI toolkits where only a fraction of your team effectively creates tools). The list of sponsors below is also an indicator that serious game teams have been using the library.
@@ -291,40 +274,49 @@ There is an auto-generated [c-api for Dear ImGui (cimgui)](https://github.com/ci
Support dear imgui
------------------
+**How can I help?**
+
+- You may participate in the [Discourse forums](https://discourse.dearimgui.org) and the GitHub [issues tracker](https://github.com/ocornut/imgui/issues).
+- You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it.
+- See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas.
+- Convince your company to financially support this project.
+
**How can I help financing further development of Dear ImGui?**
-Your contributions are keeping the library alive. If you are an individual using dear imgui, please consider donating to enable me to spend more time improving the library.
+Your contributions are keeping this project alive. The library is free as in freedom, but continued maintenance and development are a full-time endeavor. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using dear imgui, please consider reaching out for financial support. If you are an individual using dear imgui, please consider donating via Patreon or PayPal. Thank you!
+
+Individuals/hobbyists: support continued maintenance and development via the monthly Patreon:
+
[![Patreon](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/patreon_01.png)](http://www.patreon.com/imgui)
-Monthly donations via Patreon:
-
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui)
+Individuals/hobbyists: support continued maintenance and development via PayPal:
+
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S)
-One-off donations via PayPal:
-
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U)
+Businesses: support continued maintenance and development via support contracts or sponsoring:
+
_E-mail: omarcornut at gmail dot com_
-Ongoing dear imgui development is financially supported on [**Patreon**](http://www.patreon.com/imgui) and by private sponsors.
-If your company uses dear imgui, please consider financial support (e.g. sponsoring a few weeks/months of development. I can also invoice for private support, custom development etc. contact me for details: omarcornut at gmail). Thanks!
+Ongoing dear imgui development is financially supported by users and private sponsors, recently:
**Platinum-chocolate sponsors**
-- Blizzard Entertainment.
+- **Blizzard Entertainment**.
**Double-chocolate sponsors**
-- Media Molecule, Mobigame, Insomniac Games, Aras Pranckevičius, Lizardcube, Greggman, DotEmu, Nadeo, Supercell, Runner.
+- Media Molecule, Mobigame, Aras Pranckevičius, Greggman, DotEmu, Nadeo, Supercell, Runner, Aiden Koss, Kylotonn.
**Salty caramel supporters**
-- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Recognition Robotics, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko, Mercury Labs, Singularity Demo Group, Mischa Alff, Sebastien Ronsse, Lionel Landwerlin, Nikolay Ivanov, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts.
+- Recognition Robotics, ikrima, Geoffrey Evans, Mercury Labs, Singularity Demo Group, Lionel Landwerlin, Ron Gilbert, Brandon Townsend, Nikhil Deshpande, Cort Stratton, drudru, Harfang 3D, Jeff Roberts, Rainway inc, Ondra Voves, Mesh Consultants.
**Caramel supporters**
-- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, Kit framework, Josh Faust, Martin Donlon, Quinton, Felix, Andrew Belt, Codecat, Cort Stratton, Claudio Canepa, Doug McNabb, Emmanuel Julien, Guillaume Chereau, Jeffrey Slutter, Jeremiah Deckard, r-lyeh, Roger Clark, Nekith, Joshua Fisher, Malte Hoffmann, Mustafa Karaalioglu, Merlyn Morgan-Graham, Per Vognsen, Fabian Giesen, Jan Staubach, Matt Hargett, John Shearer, Jesse Chounard, kingcoopa, Miloš Tošić, Jonas Bernemann, Johan Andersson, Nathan Hartman, Michael Labbe, Tomasz Golebiowski, Louis Schnellbach, Felipe Alfonso, Jimmy Andrews, Bojan Endrovski, Robin Berg Pettersen, Rachel Crawford, Edsel Malasig, Andrew Johnson, Sean Hunter, Jordan Mellow, Nefarius Software Solutions, Laura Wieme, Robert Nix, Mick Honey, Astrofra, Jonas Lehmann, Steven Kah Hien Wong, Bartosz Bielecki, Oscar Penas, A M, Liam Moynihan, Artometa.
+- Jerome Lanquetot, Daniel Collin, Ctrl Alt Ninja, Neil Henning, Neil Blakey-Milner, Aleksei, NeiloGD, Eric, Game Atelier, Vincent Hamm, Colin Riley, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society, Josh Faust, Martin Donlon, Codecat, Doug McNabb, Emmanuel Julien, Guillaume Chereau, Jeffrey Slutter, Jeremiah Deckard, r-lyeh, Nekith, Joshua Fisher, Malte Hoffmann, Mustafa Karaalioglu, Merlyn Morgan-Graham, Per Vognsen, Fabian Giesen, Jan Staubach, Matt Hargett, John Shearer, Jesse Chounard, kingcoopa, Jonas Bernemann, Johan Andersson, Michael Labbe, Tomasz Golebiowski, Louis Schnellbach, Jimmy Andrews, Bojan Endrovski, Robin Berg Pettersen, Rachel Crawford, Andrew Johnson, Sean Hunter, Jordan Mellow, Nefarius Software Solutions, Laura Wieme, Robert Nix, Mick Honey, Steven Kah Hien Wong, Bartosz Bielecki, Oscar Penas, A M, Liam Moynihan, Artometa, Mark Lee, Dimitri Diakopoulos, Pete Goodwin.
-And all other supporters; THANK YOU!
+And all other past and present supporters; THANK YOU!
(Please contact me if you would like to be added or removed from this list)
Credits
-------
-Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com).
+Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com).
-I first discovered imgui principles at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple imgui implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it.
+I first discovered the IMGUI paradigm at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it.
Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license).
diff --git a/docs/TODO.txt b/docs/TODO.txt
index 985f7749..b32a5a0d 100644
--- a/docs/TODO.txt
+++ b/docs/TODO.txt
@@ -8,16 +8,12 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- doc/test: add a proper documentation+regression testing system (#435)
- doc/test: checklist app to verify binding/integration of imgui (test inputs, rendering, callback, etc.).
- doc/tips: tips of the day: website? applet in imgui_club?
- - project: folder or separate repository with maintained helpers (e.g. imgui_memory_editor.h, imgui_stl.h, maybe imgui_dock would be there?)
- window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690)
- window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass.
- window: auto-fit feedback loop when user relies on any dynamic layout (window width multiplier, column) appears weird to end-user. clarify.
- window: allow resizing of child windows (possibly given min/max for each axis?.)
- window: background options for child windows, border option (disable rounding).
- - window: resizing from any sides? done. > need backends to honor mouse cursors properly. (#822)
- - window: resize from borders: support some form of outer padding to make it easier to grab borders. (#822)
- - window: fix resize glitch when collapsing an AlwaysAutoResize window.
- window: begin with *p_open == false could return false.
- window: get size/pos helpers given names (see discussion in #249)
- window: a collapsed window can be stuck behind the main menu bar?
@@ -28,8 +24,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- window: expose contents size. (#1045)
- window: using SetWindowPos() inside Begin() and moving the window with the mouse reacts a very ugly glitch. We should just defer the SetWindowPos() call.
- window: GetWindowSize() returns (0,0) when not calculated? (#1045)
- - window: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate.
- window: investigate better auto-positioning for new windows.
+ - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate.
+ - window/child: the first draw command of a child window could be moved into the current draw command of the parent window (unless child+tooltip?).
+ - window/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero.
+ - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse)
- scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet.
- scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y). (2017-08-20: can't repro)
- scrolling/style: shadows on scrollable areas to denote that there is more contents
@@ -39,7 +38,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command).
- drawlist: primitives/helpers to manipulate vertices post submission, so e.g. a quad/rect can be resized to fit later submitted content, _without_ using the ChannelSplit api
- drawlist: make it easier to toggle AA per primitive, so we can use e.g. non-AA fill + AA borders more naturally
- - drawlist: non-AA strokes have gaps between points (#593, #288), especially RenderCheckmark().
+ - drawlist: non-AA strokes have gaps between points (#593, #288), glitch especially on RenderCheckmark() and ColorPicker4().
- drawlist: would be good to be able to deep copy of ImDrawData (we have a deep copy of ImDrawList now).
- drawlist: rendering: provide a way for imgui to output to a single/global vertex buffer, re-order indices only at the end of the frame (ref: https://gist.github.com/floooh/10388a0afbe08fce9e617d8aefa7d302)
- drawlist: callback: add an extra void* in ImDrawCallback to allow passing render-local data to the callback (would break API).
@@ -61,7 +60,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- widgets: activate by identifier (trigger button, focus given id)
- widgets: a way to represent "mixed" values, so e.g. all values replaced with **, including check-boxes, colors, etc. with support for multi-components widgets (e.g. SliderFloat3, make only "Y" mixed)
- - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile.
+ - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile.
- input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541)
- input text: expose CursorPos in char filter event (#816)
- input text: access public fields via a non-callback API e.g. InputTextGetState("xxx") that may return NULL if not active.
@@ -74,6 +73,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it.
- input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position.
- input text: what's the easiest way to implement a nice IP/Mac address input editor?
+ - input text: Global callback system so user can plug in an expression evaluator easily.
- input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc).
- input text multi-line: support for cut/paste without selection (cut/paste the current line)
- input text multi-line: line numbers? status bar? (follow up on #200)
@@ -93,19 +93,19 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding.
- layout: BeginGroup() needs a border option. (~#1496)
- layout: vertical alignment of mixed height items (e.g. buttons) within a same line (#1284)
-
+
- columns: sizing policy (e.g. for each column: fixed size, %, fill, distribute default size among fills) (#513, #125)
- columns: add a conditional parameter to SetColumnOffset() (#513, #125)
- - columns: headers. reorderable. (#513, #125)
+ - columns: headers. re-orderable. (#513, #125)
- columns: optional sorting modifiers (up/down), sort list so sorting can be done multi-criteria. notify user when sort order changed.
- - columns: option to alternate background colors on odd/even scanlines.
- - columns: allow columns to recurse.
- - columns: allow a same columns set to be interrupted by e.g. CollapsingHeader and resume with columns in sync when moving them.
+ - columns: option to alternate background colors on odd/even scanlines.
+ - columns: allow columns to recurse.
+ - columns: allow a same columns set to be interrupted by e.g. CollapsingHeader and resume with columns in sync when moving them.
- columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (#125)
- columns: flag to add horizontal separator above/below?
- columns/layout: setup minimum line height (equivalent of automatically calling AlignFirstTextHeightToWidgets)
-!- color: the color conversion helpers/types are a mess and needs sorting out.
+!- color: the color conversion helpers/types are a mess and needs sorting out.
- color: (api breaking) ImGui::ColorConvertXXX functions should be loose ImColorConvertXX to match imgui_internals.h
- plot: full featured plot/graph api w/ scrolling, zooming etc. all bell & whistle. why not!
@@ -122,7 +122,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- clipper: ability to run without knowing full count in advance.
- splitter/separator: formalize the splitter idiom into an official api (we want to handle n-way split) (#319)
-
+
+ - dock: merge docking branch (#2109)
- dock: A~ Unreal style document system (requires low-level controls of dockspace serialization fork/copy/delete). this is mostly working but the DockBuilderXXX api are not exposed/finished.
- dock: B: when docking outer, perform size locking on neighbors nodes the same way we do it with splitters, so other nodes are not resized.
- dock: B~ central node resizing behavior incorrect.
@@ -134,8 +135,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- dock: B~ SetNextWindowDock() calls (with conditional) -> defer everything to DockContextUpdate (repro: Documents->[X]Windows->Dock 1 elsewhere->Click Redock All
- dock: B~ tidy up tab list popup buttons features (available with manual tab-bar, see ImGuiTabBarFlags_NoTabListPopupButton code, not used by docking nodes)
- dock: B- SetNextWindowDockId(0) with a second Begin() in the frame will asserts
- - dock: B- inconsistent clipping/border 1-pixel issue (#2)
- - dock: B- fix/disable auto-resize grip on split host nodes (~#2)
+ - dock: B: resize grip drawn in host window typically appears under scrollbar.
- dock: B- SetNextWindowFocus() doesn't seem to apply if the window is hidden this frame, need repro (#4)
- dock: B- resizing a dock tree small currently has glitches (overlapping collapse and close button, etc.)
- dock: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff.
@@ -143,7 +143,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- dock: B- tab bar: make selected tab always shows its full title?
- dock: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8)
- dock: B- nav: design interactions so nav controls can dock/undock
- - dock: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockFlags_Locked?)
+ - dock: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockNodeFlags_Locked?)
- dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node!
- dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button)
- dock: B- option to remember undocked window size? (instead of keeping their docked size) (relate to #2104)
@@ -155,7 +155,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- ext: stl-ish friendly extension (imgui_stl.h) that has wrapper for std::string, std::vector etc.
- - button: provide a button that looks framed.
+ - button: provide a button that looks framed. (?)
- image/image button: misalignment on padded/bordered button?
- image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that?
- image button: not taking an explicit id is odd.
@@ -167,7 +167,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- slider: step option (#1183)
- slider style: fill % of the bar instead of positioning a drag.
- knob: rotating knob widget (#942)
+ - drag float: power/logarithmic slider and drags are weird. (#1316)
- drag float: up/down axis
+ - drag float: power != 0.0f with current value being outside the the range keeps the value stuck.
- drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits)
- combo: use clipper: make it easier to disable clipper with a single flag.
@@ -193,8 +195,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- tooltip: drag and drop with tooltip near monitor edges lose/changes its last direction instead of locking one. The drag and drop tooltip should always follow without changing direction.
- tooltip: tooltip that doesn't fit in entire screen seems to lose their "last preferred direction" and may teleport when moving mouse.
- tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic.
- - tooltip: tooltips with delay timers? or general timer policy? (instantaneous vs timed): IsItemHovered() with timer + implicit aabb-id for items with no ID. (#1485)
-
+ - tooltip: tooltips with delay timers? or general timer policy? (instantaneous vs timed): IsItemHovered() with timer + implicit aabb-id for items with no ID. (#1485)
+
- menus: calling BeginMenu() twice with a same name doesn't append as Begin() does for regular windows (#1207)
- menus: menu bars inside modal windows are acting weird.
- status-bar: add a per-window status bar helper similar to what menu-bar does.
@@ -202,7 +204,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- shortcuts,menus: global-style shortcut api e.g. "Save (CTRL+S)" -> explicit flag for recursing into closed menu
- shortcuts: programmatically access shortcuts "Focus("&Save"))
- menus: menu-bar: main menu-bar could affect clamping of windows position (~ akin to modifying DisplayMin)
- - menus: hovering from menu to menu on a menu-bar has 1 frame without any menu, which is a little annoying. ideally either 0 either longer.
+ - menus: hovering from menu to menu on a menu-bar has 1 frame without any menu, which is a little annoying. ideally either 0 either longer.
- text: selectable text (for copy) as a generic feature (ItemFlags?)
- text: proper alignment options in imgui_internal.h
@@ -223,7 +225,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437)
- stb: add defines to disable stb implementations
-!- style: better default styles. (#707)
+ - style: better default styles. (#707)
- style: add a highlighted text color (for headers, etc.)
- style: border types: out-screen, in-screen, etc. (#447)
- style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier)
@@ -244,6 +246,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- filters: handle wild-cards (with implicit leading/trailing *), reg-exprs
- filters: fuzzy matches (may use code at blog.forrestthewoods.com/4cffeed33fdb)
+ - drag and drop: releasing a drop shows the "..." tooltip for one frame - since e13e598 (#1725)
- drag and drop: have some way to know when a drag begin from BeginDragDropSource() pov.
- drag and drop: allow preview tooltip to be submitted from a different place than the drag source. (#1725)
- drag and drop: allow using with other mouse buttons (where activeid won't be set). (#1637)
@@ -256,16 +259,16 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- pie menus patterns (#434)
- markup: simple markup language for color change? (#902)
-!- font: need handling of missing glyphs by not packing/rasterizing glyph 0 of a given font.
- - font: MergeMode: flags to select overwriting or not.
- - font: MergeMode: duplicate glyphs are stored in the atlas texture which is suboptimal.
+ - font: MergeMode: flags to select overwriting or not (this is now very easy with refactored ImFontAtlasBuildWithStbTruetype)
- font: free the Alpha buffer if user only requested RGBA.
!- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions).
- font: a CalcTextHeight() helper could run faster than CalcTextSize().y
- font: enforce monospace through ImFontConfig (for icons?) + create dual ImFont output from same input, reusing rasterized data but with different glyphs/AdvanceX
- - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data
+ - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data
- font: PushFontSize API (#1018)
- font: MemoryTTF taking ownership confusing/not obvious, maybe default should be opposite?
+ - font/demo: add tools to show glyphs used by a text blob, display U16 value, list missing glyphs.
+ - font/demo: demonstrate use of ImFontGlyphRangesBuilder.
- font/atlas: add a missing Glyphs.reserve()
- font/atlas: incremental updates
- font/atlas: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier.
@@ -273,13 +276,16 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- font/draw: vertical and/or rotated text renderer (#705) - vertical is easier clipping wise
- font/draw: need to be able to specify wrap start position.
- font/draw: better reserve policy for large horizontal block of text (shouldn't reserve for all clipped lines)
- - font: imgui_freetype.h alternative renderer (#618)
- - font: optimization: for monospace font (like the default one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance (need to make sure TAB is still correct).
+ - font: optimization: for monospace font (like the default one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance (need to make sure TAB is still correct), would save on cache line.
- font: add support for kerning, probably optional. A) perhaps default to (32..128)^2 matrix ~ 9K entries = 36KB, then hash for non-ascii?. B) or sparse lookup into per-char list?
- font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize)
- font: fix AddRemapChar() to work before font has been built.
- - font: (api breaking) removed "TTF" from symbol names. also because it now supports OTF.
+ - font: what would it take to support codepoint higher than 0xFFFF? (smileys, etc.)
+ - font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF.
+ - font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer?
+ - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16 bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8?
+ - nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window"
- nav: wrap around logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping().
- nav: patterns to make it possible for arrows key to update selection
- nav: restore/find nearest navid when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name)
@@ -291,8 +297,10 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- nav: NavFlattened: init request doesn't select items that are part of a NavFlattened child
- nav: NavFlattened: cannot access menu-bar of a flattened child window with Alt/menu key (not a very common use case..).
- nav: Left within a tree node block as a fallback (ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default?)
- - nav: menus: pressing left-right on a vertically clipped menu bar tends to jump to the collapse/close buttons.
- - nav: menus: allow pressing Menu to leave a sub-menu.
+ - nav/menus: pressing left-right on a vertically clipped menu bar tends to jump to the collapse/close buttons.
+ - nav/menus: allow pressing Menu to leave a sub-menu.
+ - nav/menus: a way to access the main menu bar with Alt? (currently needs CTRL+TAB)
+ - nav/menus: when using the main menu bar, even though we restore focus after, the underlying window loses its title bar highlight during menu manipulation. could we prevent it?
- nav: simulate right-click or context activation? (SHIFT+F10)
- nav: tabs should go through most/all widgets (in submission order?).
- nav: when CTRL-Tab/windowing is active, the HoveredWindow detection doesn't take account of the window display re-ordering.
@@ -314,7 +322,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for.
- viewport: implicit/fallback Debug window can hog a zombie viewport (harmless, noisy?) > could at least clear out the reference on a per session basis?
- viewport: need to clarify how to use GetMousePos() from a user point of view.
- - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport.
+ - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport.
- platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set
- platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it).
- platform: sdl: multi-viewport + minimized window seems to break mouse wheel events (at least under Win32).
@@ -325,13 +333,12 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- inputs/io: backspace and arrows in the context of a text input could use system repeat rate.
- inputs/io: clarify/standardize/expose repeat rate and repeat delays (#1808)
- - misc: idle refresh: expose cursor blink animation timer for backend to be able to lower framerate.
+ - misc: idle: expose "woken up" boolean (set by inputs) and/or animation time (for cursor blink) for back-end to be able stop refreshing easily.
+ - misc: idle: if cursor blink if the _only_ visible animation, core imgui could rewrite vertex alpha to avoid CPU pass on ImGui:: calls.
- misc: make the ImGuiCond values linear (non-power-of-two). internal storage for ImGuiWindow can use integers to combine into flags (Why?)
- misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL)
- misc: PushItemFlag(): add a flag to disable keyboard capture when used with mouse? (#1682)
- misc: use more size_t in public api?
- - misc: ImVector: erase_unsorted() helper
- - misc: imgui_cpp: perhaps a misc/ header file with more friendly helper (e.g. type-infer versions of DragScalar, vector<> variants if appropriate for some functions).
- backend: bgfx? https://gist.github.com/RichardGale/6e2b74bc42b3005e08397236e4be0fd0
- web/emscriptem: refactor some examples to facilitate integration with emscripten main loop system. (#1713, #336)
@@ -342,7 +349,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- demo: find a way to demonstrate textures in the examples application, as it such a a common issue for new users.
- demo: add vertical separator demo
- demo: add virtual scrolling example?
- - demo: demonstration Plot offset
+ - demo: demonstrate Plot offset
- examples: window minimize, maximize (#583)
- examples: provide a zero frame-rate/idle example.
- examples: apple: example_apple should be using modern GL3.
@@ -350,6 +357,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- optimization: replace vsnprintf with stb_printf? or enable the defines/infrastructure to allow it (#1038)
- optimization: add clipping for multi-component widgets (SliderFloatX, ColorEditX, etc.). one problem is that nav branch can't easily clip parent group when there is a move request.
- optimization: add a flag to disable most of rendering, for the case where the user expect to skip it (#335)
+ - optimization: fully covered window (covered by another with non-translucent bg + WindowRounding worth of padding) may want to clip rendering.
- optimization: use another hash function than crc32, e.g. FNV1a
- optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)?
- optimization: turn some the various stack vectors into statically-sized arrays
diff --git a/.github/issue_template.md b/docs/issue_template.md
similarity index 53%
rename from .github/issue_template.md
rename to docs/issue_template.md
index 38a59532..73330b22 100644
--- a/.github/issue_template.md
+++ b/docs/issue_template.md
@@ -1,13 +1,14 @@
(Click "Preview" to turn any http URL into a clickable link)
-1. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/DISPLAYING/ADDING FONTS/WIRING INPUTS, please post on the "Getting Started" Discourse forum:
-https://discourse.dearimgui.org/c/getting-started
+1. PLEASE CAREFULLY READ:
+https://github.com/ocornut/imgui/issues/2261
-2. You may use this Issue Tracker to ask for help and submit bug reports, feature requests or suggestions that don't fit in any category of (1). PLEASE CAREFULLY READ THE CONTRIBUTING DOCUMENT before submitting any issue: https://github.com/ocornut/imgui/blob/master/.github/CONTRIBUTING.md
+2. IF YOU ARE HAVING AN ISSUE COMPILING/LINKING/RUNNING/DISPLAYING/ADDING FONTS, please post on the "Getting Started" Discourse forum:
+https://discourse.dearimgui.org/c/getting-started
-3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the CONTRIBUTING.md file linked above.
+3. PLEASE MAKE SURE that you have: read the FAQ in imgui.cpp; explored the contents of ShowDemoWindow() including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1).
-4. Delete points 1-4 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
+4. Delete points 1-4 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue.
----
@@ -18,22 +19,24 @@ _(you may also go to Demo>About Window, and click "Config/Build Information" to
Version: XXX
Branch: XXX _(master/viewport/docking/etc.)_
-**Back-end/Renderer/Compiler/OS**
+**Back-end/Renderer/Compiler/OS**
Back-ends: imgui_impl_XXX.cpp + imgui_impl_XXX.cpp _(or specify if using a custom engine/back-end)_
-Compiler: XXX _(if the question is related to building)_
-Operating System: XXX
+Compiler: XXX _(if the question is related to building or platform specific features)_
+Operating System: XXX
+
+**My Issue/Question:**
-**My Issue/Question:** _(please provide context)_
+XXX _(please provide as much context as possible)_
-XXX
+**Screenshots/Video**
-**Standalone, minimal, complete and verifiable example:** _(see CONTRIBUTING.md)_
+XXX _(you can drag files here)_
+
+**Standalone, minimal, complete and verifiable example:** _(see https://github.com/ocornut/imgui/issues/2261)_
```
// Please do not forget this!
ImGui::Begin("Example Bug");
MoreCodeToExplainMyIssue();
ImGui::End();
```
-
-**Screenshots/Video** _(you can drag files here)_
diff --git a/docs/pull_request_template.md b/docs/pull_request_template.md
new file mode 100644
index 00000000..533027c9
--- /dev/null
+++ b/docs/pull_request_template.md
@@ -0,0 +1,6 @@
+(Click "Preview" to turn any http URL into a clickable link)
+
+PLEASE CAREFULLY READ:
+https://github.com/ocornut/imgui/issues/2261
+
+(Clear this template before submitting your PR)
diff --git a/examples/README.txt b/examples/README.txt
index bffd3862..0ca44d33 100644
--- a/examples/README.txt
+++ b/examples/README.txt
@@ -26,7 +26,7 @@ This folder contains two things:
- Example applications (standalone, ready-to-build) using the aforementioned bindings.
They are the in the XXXX_example/ sub-folders.
-You can find binaries of some of those example applications at:
+You can find binaries of some of those example applications at:
http://www.miracleworld.net/imgui/binaries
@@ -36,7 +36,7 @@ You can find binaries of some of those example applications at:
- Please read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
Please read the comments and instruction at the top of each file.
-
+
- If you are using of the backend provided here, so you can copy the imgui_impl_xxx.cpp/h files
to your project and use them unmodified. Each imgui_impl_xxxx.cpp comes with its own individual
ChangeLog at the top of the .cpp files, so if you want to update them later it will be easier to
@@ -44,13 +44,13 @@ You can find binaries of some of those example applications at:
- Dear ImGui has 0 to 1 frame of lag for most behaviors, at 60 FPS your experience should be pleasant.
However, consider that OS mouse cursors are typically drawn through a specific hardware accelerated path
- and will feel smoother than common GPU rendered contents (including Dear ImGui windows).
- You may experiment with the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor itself,
+ and will feel smoother than common GPU rendered contents (including Dear ImGui windows).
+ You may experiment with the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor itself,
to visualize the lag between a hardware cursor and a software cursor. However, rendering a mouse cursor
at 60 FPS will feel slow. It might be beneficial to the user experience to switch to a software rendered
- cursor only when an interactive drag is in progress.
+ cursor only when an interactive drag is in progress.
Note that some setup or GPU drivers are likely to be causing extra lag depending on their settings.
- If you feel that dragging windows feels laggy and you are not sure who to blame: try to build an
+ If you feel that dragging windows feels laggy and you are not sure who to blame: try to build an
application drawing a shape directly under the mouse cursor.
@@ -72,17 +72,17 @@ Most the example bindings are split in 2 parts:
- Some bindings for higher level frameworks carry both "Platform" and "Renderer" parts in one file.
This is the case for Allegro 5 (imgui_impl_allegro5.cpp), Marmalade (imgui_impl_marmalade5.cpp).
- - If you use your own engine, you may decide to use some of existing bindings and/or rewrite some using
+ - If you use your own engine, you may decide to use some of existing bindings and/or rewrite some using
your own API. As a recommendation, if you are new to Dear ImGui, try using the existing binding as-is
- first, before moving on to rewrite some of the code. Although it is tempting to rewrite both of the
+ first, before moving on to rewrite some of the code. Although it is tempting to rewrite both of the
imgui_impl_xxxx files to fit under your coding style, consider that it is not necessary!
In fact, if you are new to Dear ImGui, rewriting them will almost always be harder.
- Example: your engine is built over Windows + DirectX11 but you have your own high-level rendering
+ Example: your engine is built over Windows + DirectX11 but you have your own high-level rendering
system layered over DirectX11.
- Suggestion: step 1: try using imgui_impl_win32.cpp + imgui_impl_dx11.cpp first.
- Once this work, _if_ you want you can replace the imgui_impl_dx11.cpp code with a custom renderer
- using your own functions, etc.
+ Suggestion: step 1: try using imgui_impl_win32.cpp + imgui_impl_dx11.cpp first.
+ Once this work, _if_ you want you can replace the imgui_impl_dx11.cpp code with a custom renderer
+ using your own functions, etc.
Please consider using the bindings to the lower-level platform/graphics API as-is.
Example: your engine is multi-platform (consoles, phones, etc.), you have high-level systems everywhere.
@@ -90,17 +90,17 @@ Most the example bindings are split in 2 parts:
This is counter-intuitive, but this will get you running faster! Once you better understand how imgui
works and is bound, you can rewrite the code using your own systems.
- - From Dear ImGui 1.XX we added an (optional) feature called "viewport" which allows imgui windows to be
- seamlessly detached from the main application window. This is achieved using an extra layer to the
- platform and renderer bindings, which allows imgui to communicate platform-specific requests such as
- "create an additional OS window", "create a render context", "get the OS position of this window" etc.
- When using this feature, the coupling with your OS/renderer becomes much tighter than a regular imgui
+ - From Dear ImGui 1.XX we added an (optional) feature called "viewport" which allows imgui windows to be
+ seamlessly detached from the main application window. This is achieved using an extra layer to the
+ platform and renderer bindings, which allows imgui to communicate platform-specific requests such as
+ "create an additional OS window", "create a render context", "get the OS position of this window" etc.
+ When using this feature, the coupling with your OS/renderer becomes much tighter than a regular imgui
integration. It is also much more complicated and require more work to integrate correctly.
If you are new to imgui and you are trying to integrate it into your application, first try to ignore
everything related to Viewport and Platform Windows. You'll be able to come back to it later!
Note that if you decide to use unmodified imgui_impl_xxxx.cpp files, you will automatically benefit
from improvements and fixes related to viewports and platform windows without extra work on your side.
- See 'ImGuiPlatformIO' for details.
+ See 'ImGuiPlatformIO' for details.
List of Platforms Bindings in this repository:
@@ -132,7 +132,7 @@ Third-party framework, graphics API and languages bindings are listed at:
https://github.com/ocornut/imgui/wiki/Bindings
Languages: C, C#, ChaiScript, D, Go, Haxe, Java, Lua, Odin, Pascal, PureBasic, Python, Rust, Swift...
- Frameworks: Cinder, Cocoa (OSX), Cocos2d-x, Emscripten, SFML, GML/GameMaker Studio, Irrlicht, Ogre,
+ Frameworks: Cinder, Cocoa (OSX), Cocos2d-x, Emscripten, SFML, GML/GameMaker Studio, Irrlicht, Ogre,
OpenSceneGraph, openFrameworks, LOVE, NanoRT, Nim Game Lib, Qt3d, SFML, Unreal Engine 4...
Miscellaneous: Software Renderer, RemoteImgui, etc.
@@ -142,12 +142,12 @@ Third-party framework, graphics API and languages bindings are listed at:
---------------------------------------
Building:
- Unfortunately in 2018 it is still tedious to create and maintain portable build files using external
- libraries (the kind we're using here to create a window and render 3D triangles) without relying on
+ Unfortunately in 2018 it is still tedious to create and maintain portable build files using external
+ libraries (the kind we're using here to create a window and render 3D triangles) without relying on
third party software. For most examples here I choose to provide:
- Makefiles for Linux/OSX
- Batch files for Visual Studio 2008+
- - A .sln project file for Visual Studio 2010+
+ - A .sln project file for Visual Studio 2010+
- Xcode project files for the Apple examples
Please let me know if they don't work with your setup!
You can probably just import the imgui_impl_xxx.cpp/.h files into your own codebase or compile those
@@ -157,7 +157,7 @@ Building:
example_win32_directx9/
DirectX9 example, Windows only.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx9.cpp
-
+
example_win32_directx10/
DirectX10 example, Windows only.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx10.cpp
@@ -165,64 +165,64 @@ example_win32_directx10/
example_win32_directx11/
DirectX11 example, Windows only.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx11.cpp
-
+
example_win32_directx12/
DirectX12 example, Windows only.
- This is quite long and tedious, because: DirectX12.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx12.cpp
+ This is quite long and tedious, because: DirectX12.
example_apple_metal/
OSX & iOS + Metal.
+ = main.m + imgui_impl_osx.mm + imgui_impl_metal.mm
It is based on the "cross-platform" game template provided with Xcode as of Xcode 9.
(NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.)
- = game template + imgui_impl_osx.mm + imgui_impl_metal.mm
example_apple_opengl2/
OSX + OpenGL2.
- (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.)
= main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp
+ (NB: you may still want to use GLFW or SDL which will also support Windows, Linux along with OSX.)
example_glfw_opengl2/
+ GLFW + OpenGL2 example (legacy, fixed pipeline).
+ = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp
**DO NOT USE OPENGL2 CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
**Prefer using OPENGL3 code (with gl3w/glew/glad, you can replace the OpenGL function loader)**
- GLFW + OpenGL2 example (legacy, fixed pipeline).
This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter.
If your code is using GL3+ context or any semi modern OpenGL calls, using this renderer is likely to
make things more complicated, will require your code to reset many OpenGL attributes to their initial
state, and might confuse your GPU driver. One star, not recommended.
- = main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp
example_glfw_opengl3/
- GLFW (Win32, Mac, Linux) + OpenGL3+/ES2/ES3 example (programmable pipeline, binding modern functions with GL3W).
- This uses more modern OpenGL calls and custom shaders.
- Prefer using that if you are using modern OpenGL in your application (anything with shaders).
+ GLFW (Win32, Mac, Linux) + OpenGL3+/ES2/ES3 example (programmable pipeline).
= main.cpp + imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp
-
+ This uses more modern OpenGL calls and custom shaders.
+ Prefer using that if you are using modern OpenGL in your application (anything with shaders).
+
example_glfw_vulkan/
GLFW (Win32, Mac, Linux) + Vulkan example.
- This is quite long and tedious, because: Vulkan.
= main.cpp + imgui_impl_glfw.cpp + imgui_impl_vulkan.cpp
+ This is quite long and tedious, because: Vulkan.
example_sdl_opengl2/
+ SDL2 (Win32, Mac, Linux etc.) + OpenGL example (legacy, fixed pipeline).
+ = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl2.cpp
**DO NOT USE OPENGL2 CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
**Prefer using OPENGL3 code (with gl3w/glew/glad, you can replace the OpenGL function loader)**
- SDL2 (Win32, Mac, Linux etc.) + OpenGL example (legacy, fixed pipeline).
This code is mostly provided as a reference to learn about Dear ImGui integration, because it is shorter.
If your code is using GL3+ context or any semi modern OpenGL calls, using this renderer is likely to
make things more complicated, will require your code to reset many OpenGL attributes to their initial
- state, and might confuse your GPU driver. One star, not recommended.
- = main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl2.cpp
+ state, and might confuse your GPU driver. One star, not recommended.
example_sdl_opengl3/
SDL2 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example.
- This uses more modern OpenGL calls and custom shaders.
- Prefer using that if you are using modern OpenGL in your application (anything with shaders).
= main.cpp + imgui_impl_sdl.cpp + imgui_impl_opengl3.cpp
+ This uses more modern OpenGL calls and custom shaders.
+ Prefer using that if you are using modern OpenGL in your application (anything with shaders).
example_sdl_vulkan/
SDL2 (Win32, Mac, Linux, etc.) + Vulkan example.
- This is quite long and tedious, because: Vulkan.
= main.cpp + imgui_impl_sdl.cpp + imgui_impl_vulkan.cpp
+ This is quite long and tedious, because: Vulkan.
example_allegro5/
Allegro 5 example.
diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp
index e71c2b2f..6a579a3c 100644
--- a/examples/example_allegro5/main.cpp
+++ b/examples/example_allegro5/main.cpp
@@ -29,17 +29,16 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
- // Setup Platform/Renderer bindings
->>>>>>> viewport
- ImGui_ImplAllegro5_Init(display);
-
- // Setup Style
+ // Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
+ // Setup Platform/Renderer bindings
+ ImGui_ImplAllegro5_Init(display);
+
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -69,7 +68,7 @@ int main(int, char**)
while (al_get_next_event(queue, &ev))
{
ImGui_ImplAllegro5_ProcessEvent(&ev);
- if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
+ if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
running = false;
if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE)
{
@@ -98,7 +97,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
diff --git a/examples/example_apple_metal/Shared/AppDelegate.h b/examples/example_apple_metal/Shared/AppDelegate.h
index c4632b1f..94878d94 100644
--- a/examples/example_apple_metal/Shared/AppDelegate.h
+++ b/examples/example_apple_metal/Shared/AppDelegate.h
@@ -1,4 +1,3 @@
-
#import
#if TARGET_OS_IPHONE
diff --git a/examples/example_apple_metal/Shared/AppDelegate.m b/examples/example_apple_metal/Shared/AppDelegate.m
index eabb44c1..6947eb23 100644
--- a/examples/example_apple_metal/Shared/AppDelegate.m
+++ b/examples/example_apple_metal/Shared/AppDelegate.m
@@ -1,4 +1,3 @@
-
#import "AppDelegate.h"
@implementation AppDelegate
diff --git a/examples/example_apple_metal/Shared/Renderer.h b/examples/example_apple_metal/Shared/Renderer.h
index f324915c..81fc6f54 100644
--- a/examples/example_apple_metal/Shared/Renderer.h
+++ b/examples/example_apple_metal/Shared/Renderer.h
@@ -1,4 +1,3 @@
-
#import
@interface Renderer : NSObject
diff --git a/examples/example_apple_metal/Shared/Renderer.mm b/examples/example_apple_metal/Shared/Renderer.mm
index 95218eae..efc3332b 100644
--- a/examples/example_apple_metal/Shared/Renderer.mm
+++ b/examples/example_apple_metal/Shared/Renderer.mm
@@ -1,4 +1,3 @@
-
#import "Renderer.h"
#import
@@ -26,11 +25,9 @@
IMGUI_CHECKVERSION();
ImGui::CreateContext();
- (void)ImGui::GetIO();
-
- ImGui_ImplMetal_Init(_device);
-
ImGui::StyleColorsDark();
+
+ ImGui_ImplMetal_Init(_device);
}
return self;
@@ -52,7 +49,7 @@
io.DeltaTime = 1 / float(view.preferredFramesPerSecond ?: 60);
id commandBuffer = [self.commandQueue commandBuffer];
-
+
static bool show_demo_window = true;
static bool show_another_window = false;
static float clear_color[4] = { 0.28f, 0.36f, 0.5f, 1.0f };
@@ -89,7 +86,7 @@
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -115,13 +112,13 @@
ImGui::Render();
ImDrawData *drawData = ImGui::GetDrawData();
ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder);
-
+
[renderEncoder popDebugGroup];
[renderEncoder endEncoding];
[commandBuffer presentDrawable:view.currentDrawable];
}
-
+
[commandBuffer commit];
}
diff --git a/examples/example_apple_metal/Shared/ViewController.h b/examples/example_apple_metal/Shared/ViewController.h
index a8aade13..137f93e1 100644
--- a/examples/example_apple_metal/Shared/ViewController.h
+++ b/examples/example_apple_metal/Shared/ViewController.h
@@ -1,4 +1,3 @@
-
#import
#import
#import "Renderer.h"
diff --git a/examples/example_apple_metal/Shared/ViewController.mm b/examples/example_apple_metal/Shared/ViewController.mm
index 427c0928..73040add 100644
--- a/examples/example_apple_metal/Shared/ViewController.mm
+++ b/examples/example_apple_metal/Shared/ViewController.mm
@@ -1,4 +1,3 @@
-
#import "ViewController.h"
#import "Renderer.h"
#include "imgui.h"
@@ -21,9 +20,9 @@
- (void)viewDidLoad
{
[super viewDidLoad];
-
+
self.mtkView.device = MTLCreateSystemDefaultDevice();
-
+
if (!self.mtkView.device) {
NSLog(@"Metal is not supported");
abort();
@@ -42,7 +41,7 @@
owner:self
userInfo:nil];
[self.view addTrackingArea:trackingArea];
-
+
// If we want to receive key events, we either need to be in the responder chain of the key view,
// or else we can install a local monitor. The consequence of this heavy-handed approach is that
// we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our
@@ -56,9 +55,9 @@
} else {
return event;
}
-
+
}];
-
+
ImGui_ImplOSX_Init();
#endif
}
@@ -97,7 +96,7 @@
CGPoint touchLocation = [anyTouch locationInView:self.view];
ImGuiIO &io = ImGui::GetIO();
io.MousePos = ImVec2(touchLocation.x, touchLocation.y);
-
+
BOOL hasActiveTouch = NO;
for (UITouch *touch in event.allTouches) {
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) {
diff --git a/examples/example_apple_metal/Shared/main.m b/examples/example_apple_metal/Shared/main.m
index cd8468a7..15938a90 100644
--- a/examples/example_apple_metal/Shared/main.m
+++ b/examples/example_apple_metal/Shared/main.m
@@ -1,4 +1,3 @@
-
#import
#if TARGET_OS_IPHONE
diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
index 71eca965..f1c10494 100644
--- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
+++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
@@ -231,14 +231,16 @@
TargetAttributes = {
8307E7C320E9F9C900473790 = {
CreatedOnToolsVersion = 9.4.1;
+ ProvisioningStyle = Automatic;
};
8307E7D920E9F9C900473790 = {
CreatedOnToolsVersion = 9.4.1;
+ ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 8307E7B920E9F9C700473790 /* Build configuration list for PBXProject "example_apple_metal" */;
- compatibilityVersion = "Xcode 9.3";
+ compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -444,10 +446,7 @@
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios";
PRODUCT_NAME = example_apple_metal;
SDKROOT = iphoneos;
@@ -463,10 +462,7 @@
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios";
PRODUCT_NAME = example_apple_metal;
SDKROOT = iphoneos;
@@ -483,11 +479,8 @@
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- );
- MACOSX_DEPLOYMENT_TARGET = 10.13;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos";
PRODUCT_NAME = example_apple_metal;
SDKROOT = macosx;
@@ -502,11 +495,8 @@
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- );
- MACOSX_DEPLOYMENT_TARGET = 10.13;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos";
PRODUCT_NAME = example_apple_metal;
SDKROOT = macosx;
diff --git a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
index 514c6808..20504102 100644
--- a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
+++ b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
@@ -135,11 +135,12 @@
TargetAttributes = {
4080A96A20B029B00036BA46 = {
CreatedOnToolsVersion = 9.3.1;
+ ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 4080A96620B029B00036BA46 /* Build configuration list for PBXProject "example_apple_opengl2" */;
- compatibilityVersion = "Xcode 9.3";
+ compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -286,6 +287,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_NAME = "$(TARGET_NAME)";
SYSTEM_HEADER_SEARCH_PATHS = ../libs/gl3w;
USER_HEADER_SEARCH_PATHS = ../..;
@@ -296,6 +298,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ MACOSX_DEPLOYMENT_TARGET = 10.12;
PRODUCT_NAME = "$(TARGET_NAME)";
SYSTEM_HEADER_SEARCH_PATHS = ../libs/gl3w;
USER_HEADER_SEARCH_PATHS = ../..;
diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm
index 136b26eb..d4d7a0a9 100644
--- a/examples/example_apple_opengl2/main.mm
+++ b/examples/example_apple_opengl2/main.mm
@@ -9,7 +9,7 @@
#import
#import
-//-----------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------
// ImGuiExampleView
//-----------------------------------------------------------------------------------
@@ -29,7 +29,7 @@
-(void)prepareOpenGL
{
[super prepareOpenGL];
-
+
#ifndef DEBUG
GLint swapInterval = 1;
[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
@@ -65,7 +65,7 @@
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -102,7 +102,7 @@
// Present
[[self openGLContext] flushBuffer];
-
+
if (!animationTimer)
animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES];
}
@@ -174,14 +174,14 @@
{
if (_window != nil)
return (_window);
-
+
NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 720.0);
-
+
_window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:YES];
[_window setTitle:@"Dear ImGui OSX+OpenGL2 Example"];
[_window setOpaque:YES];
[_window makeKeyAndOrderFront:NSApp];
-
+
return (_window);
}
@@ -194,12 +194,12 @@
appMenu = [[NSMenu alloc] initWithTitle:@"Dear ImGui OSX+OpenGL2 Example"];
menuItem = [appMenu addItemWithTitle:@"Quit Dear ImGui OSX+OpenGL2 Example" action:@selector(terminate:) keyEquivalent:@"q"];
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
-
+
menuItem = [[NSMenuItem alloc] init];
[menuItem setSubmenu:appMenu];
-
+
[mainMenuBar addItem:menuItem];
-
+
appMenu = nil;
[NSApp setMainMenu:mainMenuBar];
}
@@ -217,14 +217,14 @@
// Menu
[self setupMenu];
-
+
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
0
};
-
+
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
ImGuiExampleView* view = [[ImGuiExampleView alloc] initWithFrame:self.window.frame pixelFormat:format];
format = nil;
@@ -233,7 +233,7 @@
[view setWantsBestResolutionOpenGLSurface:YES];
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
[self.window setContentView:view];
-
+
if ([view openGLContext] == nil)
NSLog(@"No OpenGL Context!");
@@ -244,14 +244,14 @@
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
// Setup Platform/Renderer bindings
ImGui_ImplOSX_Init();
ImGui_ImplOpenGL2_Init();
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
diff --git a/examples/example_freeglut_opengl2/main.cpp b/examples/example_freeglut_opengl2/main.cpp
index aeaedb47..0060371b 100644
--- a/examples/example_freeglut_opengl2/main.cpp
+++ b/examples/example_freeglut_opengl2/main.cpp
@@ -32,7 +32,7 @@ void my_display_code()
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -82,7 +82,7 @@ void glut_display_func()
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
int main(int argc, char** argv)
-{
+{
// Create GLUT window
glutInit(&argc, argv);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
@@ -91,7 +91,7 @@ int main(int argc, char** argv)
glutCreateWindow("Dear ImGui FreeGLUT+OpenGL2 Example");
// Setup GLUT display function
- // We will also call ImGui_ImplFreeGLUT_InstallFuncs() to get all the other functions installed for us,
+ // We will also call ImGui_ImplFreeGLUT_InstallFuncs() to get all the other functions installed for us,
// otherwise it is possible to install our own functions and call the imgui_impl_freeglut.h functions ourselves.
glutDisplayFunc(glut_display_func);
@@ -101,18 +101,18 @@ int main(int argc, char** argv)
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
// Setup Platform/Renderer bindings
ImGui_ImplFreeGLUT_Init();
ImGui_ImplFreeGLUT_InstallFuncs();
ImGui_ImplOpenGL2_Init();
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp
index 71e481f5..4873b1f9 100644
--- a/examples/example_glfw_opengl2/main.cpp
+++ b/examples/example_glfw_opengl2/main.cpp
@@ -13,7 +13,7 @@
#include
// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
-// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
+// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
@@ -47,17 +47,25 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
+ ImGuiStyle& style = ImGui::GetStyle();
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL2_Init();
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -104,7 +112,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -133,17 +141,26 @@ int main(int, char**)
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
- //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound, but prefer using the GL3+ code.
+
+ // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
+ // you may need to backup/reset/restore current shader using the commented lines below.
+ //GLint last_program;
+ //glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
+ //glUseProgram(0);
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
+ //glUseProgram(last_program);
// Update and Render additional Platform Windows
+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
+ // For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
+ GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
+ glfwMakeContextCurrent(backup_current_context);
}
- glfwMakeContextCurrent(window);
glfwSwapBuffers(window);
}
diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp
index 3ff1cef3..bb2b1525 100644
--- a/examples/example_glfw_opengl3/main.cpp
+++ b/examples/example_glfw_opengl3/main.cpp
@@ -7,7 +7,7 @@
#include "imgui_impl_opengl3.h"
#include
-// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
+// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
@@ -21,10 +21,10 @@
#endif
// Include glfw3.h after our OpenGL definitions
-#include
+#include
// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
-// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
+// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
@@ -93,17 +93,21 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
- // Setup Platform/Renderer bindings
- ImGui_ImplGlfw_InitForOpenGL(window, true);
- ImGui_ImplOpenGL3_Init(glsl_version);
-
- // Setup Style
+ // Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle& style = ImGui::GetStyle();
- style.WindowRounding = 0.0f; // When viewports are enabled it is preferable to disable WinodwRounding
- style.Colors[ImGuiCol_WindowBg].w = 1.0f; // When viewports are enabled it is preferable to disable WindowBg alpha
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
+ // Setup Platform/Renderer bindings
+ ImGui_ImplGlfw_InitForOpenGL(window, true);
+ ImGui_ImplOpenGL3_Init(glsl_version);
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
@@ -179,7 +183,6 @@ int main(int, char**)
// Rendering
ImGui::Render();
int display_w, display_h;
- glfwMakeContextCurrent(window);
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
@@ -187,13 +190,16 @@ int main(int, char**)
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// Update and Render additional Platform Windows
+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
+ // For this specific demo app we could also call glfwMakeContextCurrent(window) directly)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
+ GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
+ glfwMakeContextCurrent(backup_current_context);
}
- glfwMakeContextCurrent(window);
glfwSwapBuffers(window);
}
diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp
index dde6fa28..b2e902e3 100644
--- a/examples/example_glfw_vulkan/main.cpp
+++ b/examples/example_glfw_vulkan/main.cpp
@@ -12,7 +12,7 @@
#include
// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
-// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
+// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
@@ -361,6 +361,18 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
+ ImGuiStyle& style = ImGui::GetStyle();
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForVulkan(window, true);
ImGui_ImplVulkan_InitInfo init_info = {};
@@ -375,13 +387,9 @@ int main(int, char**)
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -463,7 +471,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
diff --git a/examples/example_marmalade/main.cpp b/examples/example_marmalade/main.cpp
index ebbe9b3a..026b0ec7 100644
--- a/examples/example_marmalade/main.cpp
+++ b/examples/example_marmalade/main.cpp
@@ -23,16 +23,16 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
- // Setup Platform/Renderer bindings
- ImGui_Marmalade_Init(true);
-
- // Setup Style
+ // Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
+ // Setup Platform/Renderer bindings
+ ImGui_Marmalade_Init(true);
+
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -82,7 +82,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp
index 1bfb924e..c69c9489 100644
--- a/examples/example_sdl_opengl2/main.cpp
+++ b/examples/example_sdl_opengl2/main.cpp
@@ -32,6 +32,7 @@ int main(int, char**)
SDL_GetCurrentDisplayMode(0, ¤t);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
+ SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync
// Setup Dear ImGui context
@@ -44,17 +45,25 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
+ ImGuiStyle& style = ImGui::GetStyle();
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
// Setup Platform/Renderer bindings
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
ImGui_ImplOpenGL2_Init();
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -108,7 +117,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -139,13 +148,17 @@ int main(int, char**)
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
// Update and Render additional Platform Windows
+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
+ // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
+ SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
+ SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
+ SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
}
- SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SwapWindow(window);
}
diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp
index a5a82a7d..a6e164a3 100644
--- a/examples/example_sdl_opengl3/main.cpp
+++ b/examples/example_sdl_opengl3/main.cpp
@@ -9,7 +9,7 @@
#include
#include
-// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
+// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
@@ -56,6 +56,7 @@ int main(int, char**)
SDL_GetCurrentDisplayMode(0, ¤t);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
+ SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync
// Initialize OpenGL loader
@@ -84,21 +85,25 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
- // Setup Platform/Renderer bindings
- ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
- ImGui_ImplOpenGL3_Init(glsl_version);
-
- // Setup Style
+ // Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle& style = ImGui::GetStyle();
- style.WindowRounding = 0.0f; // When viewports are enabled it is preferable to disable WinodwRounding
- style.Colors[ImGuiCol_WindowBg].w = 1.0f; // When viewports are enabled it is preferable to disable WindowBg alpha
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
+ // Setup Platform/Renderer bindings
+ ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
+ ImGui_ImplOpenGL3_Init(glsl_version);
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -154,7 +159,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -178,20 +183,23 @@ int main(int, char**)
// Rendering
ImGui::Render();
- SDL_GL_MakeCurrent(window, gl_context);
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// Update and Render additional Platform Windows
+ // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
+ // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
+ SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
+ SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
+ SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
}
- SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SwapWindow(window);
}
diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp
index 720477ac..87ed6265 100644
--- a/examples/example_sdl_vulkan/main.cpp
+++ b/examples/example_sdl_vulkan/main.cpp
@@ -342,6 +342,18 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
+ ImGuiStyle& style = ImGui::GetStyle();
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
// Setup Platform/Renderer bindings
ImGui_ImplSDL2_InitForVulkan(window);
ImGui_ImplVulkan_InitInfo init_info = {};
@@ -356,13 +368,9 @@ int main(int, char**)
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -424,7 +432,7 @@ int main(int, char**)
ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT)
done = true;
- if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
+ if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED && event.window.windowID == SDL_GetWindowID(window))
ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &g_WindowData, g_Allocator, (int)event.window.data1, (int)event.window.data2);
}
@@ -448,7 +456,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -474,7 +482,7 @@ int main(int, char**)
ImGui::Render();
memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
FrameRender(wd);
-
+
// Update and Render additional Platform Windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp
index b7ba1642..8e0e8ec3 100644
--- a/examples/example_win32_directx10/main.cpp
+++ b/examples/example_win32_directx10/main.cpp
@@ -98,13 +98,13 @@ int main(int, char**)
// Create application window
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL };
RegisterClassEx(&wc);
- HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX10 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
+ HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX10 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
if (CreateDeviceD3D(hwnd) < 0)
{
CleanupDeviceD3D();
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 1;
}
@@ -122,17 +122,25 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
+ ImGuiStyle& style = ImGui::GetStyle();
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
// Setup Platform/Renderer bindings
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX10_Init(g_pd3dDevice);
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -186,7 +194,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -231,7 +239,7 @@ int main(int, char**)
CleanupDeviceD3D();
DestroyWindow(hwnd);
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp
index 5fd98c08..a8156cac 100644
--- a/examples/example_win32_directx11/main.cpp
+++ b/examples/example_win32_directx11/main.cpp
@@ -114,13 +114,13 @@ int main(int, char**)
// Create application window
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL };
RegisterClassEx(&wc);
- HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX11 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
+ HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX11 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
if (CreateDeviceD3D(hwnd) < 0)
{
CleanupDeviceD3D();
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 1;
}
@@ -139,24 +139,30 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: THIS CURRENTLY DOESN'T WORK AS EXPECTED. DON'T USE IN USER APP!
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // FIXME-DPI
- io.ConfigResizeWindowsFromEdges = true;
- io.ConfigDockingWithShift = true;
+ //io.ConfigViewportsNoAutoMerge = true;
+ //io.ConfigViewportsNoTaskBarIcon = false;
+ //io.ConfigDockingTabBarOnSingleWindows = true;
+ //io.ConfigDockingTransparentPayload = true;
- // Setup Platform/Renderer bindings
- ImGui_ImplWin32_Init(hwnd);
- ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
-
- // Setup Style
+ // Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle& style = ImGui::GetStyle();
- style.WindowRounding = 0.0f; // When viewports are enabled it is preferable to disable WinodwRounding
- style.Colors[ImGuiCol_WindowBg].w = 1.0f; // When viewports are enabled it is preferable to disable WindowBg alpha
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
+ // Setup Platform/Renderer bindings
+ ImGui_ImplWin32_Init(hwnd);
+ ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -211,7 +217,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -256,7 +262,7 @@ int main(int, char**)
CleanupDeviceD3D();
DestroyWindow(hwnd);
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj b/examples/example_win32_directx12/example_win32_directx12.vcxproj
index 38c83351..dabd6d84 100644
--- a/examples/example_win32_directx12/example_win32_directx12.vcxproj
+++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj
@@ -21,7 +21,7 @@
{b4cf9797-519d-4afe-a8f4-5141a6b521d3}
example_win32_directx12
- 10.0.16299.0
+ 10.0.14393.0
diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp
index c9c2e337..54bc7524 100644
--- a/examples/example_win32_directx12/main.cpp
+++ b/examples/example_win32_directx12/main.cpp
@@ -164,7 +164,7 @@ HRESULT CreateDeviceD3D(HWND hWnd)
SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
- for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
+ for (UINT i = 0; i < NUM_BACK_BUFFERS; i++)
{
g_mainRenderTargetDescriptor[i] = rtvHandle;
rtvHandle.ptr += rtvDescriptorSize;
@@ -272,13 +272,13 @@ int main(int, char**)
// Create application window
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL };
RegisterClassEx(&wc);
- HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX12 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
+ HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX12 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
if (CreateDeviceD3D(hwnd) < 0)
{
CleanupDeviceD3D();
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 1;
}
@@ -296,20 +296,28 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
+ // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
+ ImGuiStyle& style = ImGui::GetStyle();
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ style.WindowRounding = 0.0f;
+ style.Colors[ImGuiCol_WindowBg].w = 1.0f;
+ }
+
// Setup Platform/Renderer bindings
ImGui_ImplWin32_Init(hwnd);
- ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT,
+ ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT,
DXGI_FORMAT_R8G8B8A8_UNORM,
- g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
+ g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart());
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -363,7 +371,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -435,7 +443,7 @@ int main(int, char**)
CleanupDeviceD3D();
DestroyWindow(hwnd);
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp
index 2b7e187c..931e5f51 100644
--- a/examples/example_win32_directx9/main.cpp
+++ b/examples/example_win32_directx9/main.cpp
@@ -49,13 +49,13 @@ int main(int, char**)
// Create application window
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL };
RegisterClassEx(&wc);
- HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX9 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
+ HWND hwnd = CreateWindow(wc.lpszClassName, _T("Dear ImGui DirectX9 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
// Initialize Direct3D
LPDIRECT3D9 pD3D;
if ((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
@@ -71,7 +71,7 @@ int main(int, char**)
if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0)
{
pD3D->Release();
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
@@ -85,17 +85,17 @@ int main(int, char**)
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
+ // Setup Dear ImGui style
+ ImGui::StyleColorsDark();
+ //ImGui::StyleColorsClassic();
+
// Setup Platform/Renderer bindings
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX9_Init(g_pd3dDevice);
- // Setup Style
- ImGui::StyleColorsDark();
- //ImGui::StyleColorsClassic();
-
// Load Fonts
- // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
- // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
+ // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
+ // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'misc/fonts/README.txt' for more instructions and details.
@@ -151,7 +151,7 @@ int main(int, char**)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
- ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
+ ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
@@ -204,7 +204,7 @@ int main(int, char**)
if (g_pd3dDevice) g_pd3dDevice->Release();
if (pD3D) pD3D->Release();
DestroyWindow(hwnd);
- UnregisterClass(_T("ImGui Example"), wc.hInstance);
+ UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}
diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp
index 004638e8..8d534516 100644
--- a/examples/imgui_impl_allegro5.cpp
+++ b/examples/imgui_impl_allegro5.cpp
@@ -280,9 +280,14 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
void ImGui_ImplAllegro5_Shutdown()
{
ImGui_ImplAllegro5_InvalidateDeviceObjects();
+
g_Display = NULL;
+ g_Time = 0.0;
+
+ if (g_VertexDecl)
+ al_destroy_vertex_decl(g_VertexDecl);
+ g_VertexDecl = NULL;
- // Destroy last known clipboard data
if (g_ClipboardTextData)
al_free(g_ClipboardTextData);
g_ClipboardTextData = NULL;
diff --git a/examples/imgui_impl_dx10.cpp b/examples/imgui_impl_dx10.cpp
index d230ede9..de3c9e38 100644
--- a/examples/imgui_impl_dx10.cpp
+++ b/examples/imgui_impl_dx10.cpp
@@ -9,7 +9,7 @@
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
-// CHANGELOG
+// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
@@ -317,9 +317,9 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
ImGui_ImplDX10_InvalidateDeviceObjects();
// By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
- // If you would like to use this DX10 sample code but remove this dependency you can:
+ // If you would like to use this DX10 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
- // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
// Create the vertex shader
@@ -359,7 +359,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
return false;
// Create the input layout
- D3D10_INPUT_ELEMENT_DESC local_layout[] =
+ D3D10_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
diff --git a/examples/imgui_impl_dx11.cpp b/examples/imgui_impl_dx11.cpp
index ca3a0708..9a242784 100644
--- a/examples/imgui_impl_dx11.cpp
+++ b/examples/imgui_impl_dx11.cpp
@@ -324,9 +324,9 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
ImGui_ImplDX11_InvalidateDeviceObjects();
// By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
- // If you would like to use this DX11 sample code but remove this dependency you can:
+ // If you would like to use this DX11 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
- // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
// Create the vertex shader
@@ -366,7 +366,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
return false;
// Create the input layout
- D3D11_INPUT_ELEMENT_DESC local_layout[] =
+ D3D11_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
diff --git a/examples/imgui_impl_dx12.cpp b/examples/imgui_impl_dx12.cpp
index 7268a2e8..0325435e 100644
--- a/examples/imgui_impl_dx12.cpp
+++ b/examples/imgui_impl_dx12.cpp
@@ -441,9 +441,9 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
}
// By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
- // If you would like to use this DX12 sample code but remove this dependency you can:
+ // If you would like to use this DX12 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
- // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
diff --git a/examples/imgui_impl_dx12.h b/examples/imgui_impl_dx12.h
index 7ead88e6..e5b9dc4e 100644
--- a/examples/imgui_impl_dx12.h
+++ b/examples/imgui_impl_dx12.h
@@ -19,7 +19,7 @@ struct D3D12_CPU_DESCRIPTOR_HANDLE;
struct D3D12_GPU_DESCRIPTOR_HANDLE;
// cmd_list is the command list that the implementation will use to render imgui draw lists.
-// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
+// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format,
diff --git a/examples/imgui_impl_dx9.cpp b/examples/imgui_impl_dx9.cpp
index cb026763..3653ec25 100644
--- a/examples/imgui_impl_dx9.cpp
+++ b/examples/imgui_impl_dx9.cpp
@@ -8,8 +8,9 @@
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
-// CHANGELOG
+// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
+// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
@@ -131,6 +132,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
+ g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
@@ -148,14 +150,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
float T = draw_data->DisplayPos.y + 0.5f;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
- D3DMATRIX mat_identity = { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } };
+ D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
D3DMATRIX mat_projection =
- {
+ { { {
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
- (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f,
- };
+ (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
+ } } };
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
diff --git a/examples/imgui_impl_freeglut.cpp b/examples/imgui_impl_freeglut.cpp
index 2122e307..42d56417 100644
--- a/examples/imgui_impl_freeglut.cpp
+++ b/examples/imgui_impl_freeglut.cpp
@@ -103,7 +103,7 @@ void ImGui_ImplFreeGLUT_KeyboardFunc(unsigned char c, int x, int y)
if (c >= 32)
io.AddInputCharacter((unsigned short)c);
- // Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
+ // Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.
if (c >= 1 && c <= 26)
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = true;
diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp
index 2c4c9cb6..07df5cc5 100644
--- a/examples/imgui_impl_glfw.cpp
+++ b/examples/imgui_impl_glfw.cpp
@@ -1,6 +1,7 @@
// dear imgui: Platform Binding for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
+// (Requires: GLFW 3.1+)
// Implemented features:
// [X] Platform: Clipboard support.
@@ -141,7 +142,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
-#if GLFW_HAS_GLFW_HOVERED
+#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
#endif
io.BackendPlatformName = "imgui_impl_glfw";
@@ -181,7 +182,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
-
+
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
g_PrevUserCallbackMousebutton = NULL;
g_PrevUserCallbackScroll = NULL;
@@ -264,14 +265,32 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
{
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
- io.MousePos = ImVec2((float)mouse_x + viewport->Pos.x, (float)mouse_y + viewport->Pos.y);
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
+ int window_x, window_y;
+ glfwGetWindowPos(window, &window_x, &window_y);
+ io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y);
+ }
+ else
+ {
+ // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
+ io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
+ }
}
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0;
}
-#if GLFW_HAS_GLFW_HOVERED
- io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
+ // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
+ // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
+ // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
+ // - This is _regardless_ of whether another viewport is focused or being dragged from.
+ // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the
+ // rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows.
+ // [GLFW] FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
+ // See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
+#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32)
if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !(viewport->Flags & ImGuiViewportFlags_NoInputs))
io.MouseHoveredViewport = viewport->ID;
#endif
@@ -307,9 +326,9 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
void ImGui_ImplGlfw_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
- IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame()
+ IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
- // Setup display size
+ // Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
glfwGetWindowSize(g_Window, &w, &h);
@@ -327,7 +346,7 @@ void ImGui_ImplGlfw_NewFrame()
ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseCursor();
- // Gamepad navigation mapping [BETA]
+ // Gamepad navigation mapping
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)
{
diff --git a/examples/imgui_impl_metal.mm b/examples/imgui_impl_metal.mm
index 56abda58..24b9bf68 100644
--- a/examples/imgui_impl_metal.mm
+++ b/examples/imgui_impl_metal.mm
@@ -19,7 +19,7 @@
#include "imgui_impl_metal.h"
#import
-#import
+// #import // Not suported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...)
#import
#pragma mark - Support classes
@@ -75,7 +75,7 @@ bool ImGui_ImplMetal_Init(id device)
dispatch_once(&onceToken, ^{
g_sharedMetalContext = [[MetalContext alloc] init];
});
-
+
ImGui_ImplMetal_CreateDeviceObjects(device);
return true;
@@ -102,7 +102,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id
bool ImGui_ImplMetal_CreateFontsTexture(id device)
{
[g_sharedMetalContext makeFontTextureWithDevice:device];
-
+
ImGuiIO& io = ImGui::GetIO();
io.Fonts->TexID = (__bridge void *)g_sharedMetalContext.fontTexture; // ImTextureID == void*
@@ -134,9 +134,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
#pragma mark - MetalBuffer implementation
@implementation MetalBuffer
-- (instancetype)initWithBuffer:(id)buffer
+- (instancetype)initWithBuffer:(id)buffer
{
- if ((self = [super init]))
+ if ((self = [super init]))
{
_buffer = buffer;
_lastReuseTime = [NSDate date].timeIntervalSince1970;
@@ -148,9 +148,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
#pragma mark - FramebufferDescriptor implementation
@implementation FramebufferDescriptor
-- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor
+- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor
{
- if ((self = [super init]))
+ if ((self = [super init]))
{
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
@@ -160,7 +160,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return self;
}
-- (nonnull id)copyWithZone:(nullable NSZone *)zone
+- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init];
copy.sampleCount = self.sampleCount;
@@ -170,7 +170,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return copy;
}
-- (NSUInteger)hash
+- (NSUInteger)hash
{
NSUInteger sc = _sampleCount & 0x3;
NSUInteger cf = _colorPixelFormat & 0x3FF;
@@ -180,7 +180,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return hash;
}
-- (BOOL)isEqual:(id)object
+- (BOOL)isEqual:(id)object
{
FramebufferDescriptor *other = object;
if (![other isKindOfClass:[FramebufferDescriptor class]])
@@ -197,7 +197,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
@implementation MetalContext
- (instancetype)init {
- if ((self = [super init]))
+ if ((self = [super init]))
{
_renderPipelineStateCache = [NSMutableDictionary dictionary];
_bufferCache = [NSMutableArray array];
@@ -206,7 +206,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return self;
}
-- (void)makeDeviceObjectsWithDevice:(id)device
+- (void)makeDeviceObjectsWithDevice:(id)device
{
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
depthStencilDescriptor.depthWriteEnabled = NO;
@@ -218,7 +218,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
// You can make that change in your implementation.
-- (void)makeFontTextureWithDevice:(id)device
+- (void)makeFontTextureWithDevice:(id)device
{
ImGuiIO &io = ImGui::GetIO();
unsigned char* pixels;
@@ -239,17 +239,17 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
self.fontTexture = texture;
}
-- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device
+- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device
{
NSTimeInterval now = [NSDate date].timeIntervalSince1970;
-
+
// Purge old buffers that haven't been useful for a while
- if (now - self.lastBufferCachePurge > 1.0)
+ if (now - self.lastBufferCachePurge > 1.0)
{
NSMutableArray *survivors = [NSMutableArray array];
- for (MetalBuffer *candidate in self.bufferCache)
+ for (MetalBuffer *candidate in self.bufferCache)
{
- if (candidate.lastReuseTime > self.lastBufferCachePurge)
+ if (candidate.lastReuseTime > self.lastBufferCachePurge)
{
[survivors addObject:candidate];
}
@@ -257,51 +257,51 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
self.bufferCache = [survivors mutableCopy];
self.lastBufferCachePurge = now;
}
-
+
// See if we have a buffer we can reuse
MetalBuffer *bestCandidate = nil;
- for (MetalBuffer *candidate in self.bufferCache)
+ for (MetalBuffer *candidate in self.bufferCache)
if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
bestCandidate = candidate;
-
- if (bestCandidate != nil)
+
+ if (bestCandidate != nil)
{
[self.bufferCache removeObject:bestCandidate];
bestCandidate.lastReuseTime = now;
return bestCandidate;
}
-
+
// No luck; make a new buffer
id backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
return [[MetalBuffer alloc] initWithBuffer:backing];
}
-- (void)enqueueReusableBuffer:(MetalBuffer *)buffer
+- (void)enqueueReusableBuffer:(MetalBuffer *)buffer
{
[self.bufferCache addObject:buffer];
}
-- (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device
+- (_Nullable id)renderPipelineStateForFrameAndDevice:(id)device
{
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
// Thie hit rate for this cache should be very near 100%.
id renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];
-
- if (renderPipelineState == nil)
+
+ if (renderPipelineState == nil)
{
// No luck; make a new render pipeline state
renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];
// Cache render pipeline state for later reuse
self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState;
}
-
+
return renderPipelineState;
}
- (id)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id)device
{
NSError *error = nil;
-
+
NSString *shaderSource = @""
"#include \n"
"using namespace metal;\n"
@@ -337,23 +337,23 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
" half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
" return half4(in.color) * texColor;\n"
"}\n";
-
+
id library = [device newLibraryWithSource:shaderSource options:nil error:&error];
- if (library == nil)
+ if (library == nil)
{
NSLog(@"Error: failed to create Metal library: %@", error);
return nil;
}
-
+
id vertexFunction = [library newFunctionWithName:@"vertex_main"];
id fragmentFunction = [library newFunctionWithName:@"fragment_main"];
-
- if (vertexFunction == nil || fragmentFunction == nil)
+
+ if (vertexFunction == nil || fragmentFunction == nil)
{
NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
return nil;
}
-
+
MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
@@ -367,7 +367,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
vertexDescriptor.layouts[0].stepRate = 1;
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
-
+
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineDescriptor.vertexFunction = vertexFunction;
pipelineDescriptor.fragmentFunction = fragmentFunction;
@@ -383,17 +383,17 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
-
+
id renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
- if (error != nil)
+ if (error != nil)
{
NSLog(@"Error: failed to create Metal pipeline state: %@", error);
}
-
+
return renderPipelineState;
}
-- (void)emptyRenderPipelineStateCache
+- (void)emptyRenderPipelineStateCache
{
[self.renderPipelineStateCache removeAllObjects];
}
@@ -409,21 +409,21 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)
return;
drawData->ScaleClipRects(io.DisplayFramebufferScale);
-
+
[commandEncoder setCullMode:MTLCullModeNone];
[commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState];
-
+
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
// draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
- MTLViewport viewport =
- {
+ MTLViewport viewport =
+ {
.originX = 0.0,
.originY = 0.0,
.width = double(fb_width),
.height = double(fb_height),
.znear = 0.0,
- .zfar = 1.0
+ .zfar = 1.0
};
[commandEncoder setViewport:viewport];
float L = drawData->DisplayPos.x;
@@ -439,26 +439,26 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
};
-
+
[commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
-
+
size_t vertexBufferLength = 0;
size_t indexBufferLength = 0;
- for (int n = 0; n < drawData->CmdListsCount; n++)
+ for (int n = 0; n < drawData->CmdListsCount; n++)
{
const ImDrawList* cmd_list = drawData->CmdLists[n];
vertexBufferLength += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
indexBufferLength += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
}
-
+
MetalBuffer *vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
MetalBuffer *indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
-
+
id renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device];
[commandEncoder setRenderPipelineState:renderPipelineState];
-
+
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
-
+
size_t vertexBufferOffset = 0;
size_t indexBufferOffset = 0;
ImVec2 pos = drawData->DisplayPos;
@@ -466,12 +466,12 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
{
const ImDrawList* cmd_list = drawData->CmdLists[n];
ImDrawIdx idx_buffer_offset = 0;
-
+
memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
-
+
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
-
+
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
@@ -491,8 +491,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
.width = NSUInteger(clip_rect.z - clip_rect.x),
.height = NSUInteger(clip_rect.w - clip_rect.y) };
[commandEncoder setScissorRect:scissorRect];
-
-
+
+
// Bind texture, Draw
if (pcmd->TextureId != NULL)
[commandEncoder setFragmentTexture:(__bridge id)(pcmd->TextureId) atIndex:0];
@@ -505,13 +505,13 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
}
idx_buffer_offset += pcmd->ElemCount * sizeof(ImDrawIdx);
}
-
+
vertexBufferOffset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
indexBufferOffset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
}
-
+
__weak id weakSelf = self;
- [commandBuffer addCompletedHandler:^(id)
+ [commandBuffer addCompletedHandler:^(id)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf enqueueReusableBuffer:vertexBuffer];
diff --git a/examples/imgui_impl_opengl2.cpp b/examples/imgui_impl_opengl2.cpp
index be210709..9e32ea2f 100644
--- a/examples/imgui_impl_opengl2.cpp
+++ b/examples/imgui_impl_opengl2.cpp
@@ -14,10 +14,10 @@
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
-// confuse your GPU driver.
+// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
-// CHANGELOG
+// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
@@ -83,7 +83,7 @@ void ImGui_ImplOpenGL2_NewFrame()
// OpenGL2 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
-// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
+// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
@@ -99,7 +99,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
- GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
+ GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -113,7 +113,14 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound
+
+ // If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
+ // you may need to backup/reset/restore current shader using the lines below. DO NOT MODIFY THIS FILE! Add the code in your calling function:
+ // GLint last_program;
+ // glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
+ // glUseProgram(0);
+ // ImGui_ImplOpenGL2_RenderDrawData(...);
+ // glUseProgram(last_program)
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is (0,0) for single viewport apps.
diff --git a/examples/imgui_impl_opengl2.h b/examples/imgui_impl_opengl2.h
index 7ab9cebf..b77c30af 100644
--- a/examples/imgui_impl_opengl2.h
+++ b/examples/imgui_impl_opengl2.h
@@ -14,7 +14,7 @@
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
-// confuse your GPU driver.
+// confuse your GPU driver.
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
#pragma once
diff --git a/examples/imgui_impl_opengl3.cpp b/examples/imgui_impl_opengl3.cpp
index 6f62cb8b..4459c215 100644
--- a/examples/imgui_impl_opengl3.cpp
+++ b/examples/imgui_impl_opengl3.cpp
@@ -78,7 +78,7 @@
#include // Use GL ES 3
#else
// Regular OpenGL
-// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
+// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
diff --git a/examples/imgui_impl_opengl3.h b/examples/imgui_impl_opengl3.h
index 387bcae3..e7ee13ac 100644
--- a/examples/imgui_impl_opengl3.h
+++ b/examples/imgui_impl_opengl3.h
@@ -10,9 +10,9 @@
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
-// About OpenGL function loaders:
-// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
-// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
+// About OpenGL function loaders:
+// About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually.
+// Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad.
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
// About GLSL version:
diff --git a/examples/imgui_impl_osx.mm b/examples/imgui_impl_osx.mm
index af2f831a..e5a027b8 100644
--- a/examples/imgui_impl_osx.mm
+++ b/examples/imgui_impl_osx.mm
@@ -54,14 +54,14 @@ bool ImGui_ImplOSX_Init()
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
-
+
io.SetClipboardTextFn = [](void*, const char* str) -> void
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
[pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString];
};
-
+
io.GetClipboardTextFn = [](void*) -> const char*
{
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
@@ -72,7 +72,7 @@ bool ImGui_ImplOSX_Init()
NSString* string = [pasteboard stringForType:NSPasteboardTypeString];
if (string == nil)
return NULL;
-
+
const char* string_c = (const char*)[string UTF8String];
size_t string_len = strlen(string_c);
static ImVector s_clipboard;
@@ -80,7 +80,7 @@ bool ImGui_ImplOSX_Init()
strcpy(s_clipboard.Data, string_c);
return s_clipboard.Data;
};
-
+
return true;
}
@@ -236,6 +236,6 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
resetKeys();
return io.WantCaptureKeyboard;
}
-
+
return false;
}
diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp
index 7ef8dec0..e1c505f5 100644
--- a/examples/imgui_impl_sdl.cpp
+++ b/examples/imgui_impl_sdl.cpp
@@ -1,6 +1,7 @@
// dear imgui: Platform Binding for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
+// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
@@ -19,19 +20,20 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
+// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
-// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
+// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
-// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
+// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
@@ -42,11 +44,14 @@
#include "imgui_impl_sdl.h"
// SDL
-// (the multi-viewports feature requires SDL features supported from SDL 2.0.5+)
+// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
#include
#include
-#define SDL_HAS_WARP_MOUSE_GLOBAL SDL_VERSION_ATLEAST(2,0,4)
-#define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4)
+#if defined(__APPLE__)
+#include "TargetConditionals.h"
+#endif
+
+#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5)
@@ -149,10 +154,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
-#if SDL_HAS_WARP_MOUSE_GLOBAL
- io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
-#endif
-#if SDL_HAS_CAPTURE_MOUSE
+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
#endif
io.BackendPlatformName = "imgui_impl_sdl";
@@ -213,9 +215,9 @@ bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
{
- #if !SDL_HAS_VULKAN
+#if !SDL_HAS_VULKAN
IM_ASSERT(0 && "Unsupported");
- #endif
+#endif
return ImGui_ImplSDL2_Init(window, NULL);
}
@@ -235,53 +237,72 @@ void ImGui_ImplSDL2_Shutdown()
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
}
+// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
{
ImGuiIO& io = ImGui::GetIO();
io.MouseHoveredViewport = 0;
- // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
- // (When multi-viewports are enabled, all imgui positions are same as OS positions.)
-#if SDL_HAS_WARP_MOUSE_GLOBAL
- if (!io.WantSetMousePos)
- io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
- else if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
- SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
- else
- SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y);
-#else
- io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
+ // [1]
+ // Only when requested by io.WantSetMousePos: set OS mouse pos from Dear ImGui mouse pos.
+ // (rarely used, mostly when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
+ if (io.WantSetMousePos)
+ {
+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y);
+ else
#endif
-
- int mx, my;
- Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
- io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
+ SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
+ }
+ else
+ {
+ io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
+ }
+
+ // [2]
+ // Set Dear ImGui mouse pos from OS mouse pos + get buttons. (this is the common behavior)
+ int mouse_x_local, mouse_y_local;
+ Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local);
+ io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
-#if SDL_HAS_CAPTURE_MOUSE && !defined(__EMSCRIPTEN__)
- SDL_Window* focused_window = SDL_GetKeyboardFocus();
- if (focused_window)
+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
+
+ // SDL 2.0.4 and later has SDL_GetGlobalMouseState() and SDL_CaptureMouse()
+ int mouse_x_global, mouse_y_global;
+ SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
+
+#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
- // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
- // The creation of new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
- int wx, wy;
- SDL_GetWindowPosition(focused_window, &wx, &wy);
- SDL_GetGlobalMouseState(&mx, &my);
- mx -= wx;
- my -= wy;
+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
+ if (SDL_Window* focused_window = SDL_GetKeyboardFocus())
+ if (ImGui::FindViewportByPlatformHandle((void*)focused_window) != NULL)
+ io.MousePos = ImVec2((float)mouse_x_global, (float)mouse_y_global);
+ }
+ else
+#endif
+ {
+ // Single-viewport mode: mouse position in client window coordinatesio.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
+ if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
+ {
+ int window_x, window_y;
+ SDL_GetWindowPosition(g_Window, &window_x, &window_y);
+ io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
+ }
}
- if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)focused_window))
- io.MousePos = ImVec2(viewport->Pos.x + (float)mx, viewport->Pos.y + (float)my);
- // We already retrieve global mouse position, SDL_CaptureMouse() also let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't trigger the OS window resize cursor
+ // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
// The function is only supported from SDL 2.0.4 (released Jan 2016)
bool any_mouse_button_down = ImGui::IsAnyMouseDown();
SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
#else
+ // SDL 2.0.3 and before: single-viewport only
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
- io.MousePos = ImVec2((float)mx, (float)my);
+ io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local);
#endif
}
@@ -308,7 +329,7 @@ static void ImGui_ImplSDL2_UpdateMouseCursor()
void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
{
ImGuiIO& io = ImGui::GetIO();
- IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame()
+ IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
int w, h;
diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp
index e863f64a..77675b2c 100644
--- a/examples/imgui_impl_vulkan.cpp
+++ b/examples/imgui_impl_vulkan.cpp
@@ -9,7 +9,7 @@
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
-// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
+// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
// CHANGELOG
@@ -315,7 +315,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
-
+
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);
}
@@ -746,11 +746,11 @@ void ImGui_ImplVulkan_NewFrame()
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
//-------------------------------------------------------------------------
-// You probably do NOT need to use or care about those functions.
+// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
// 2) the upcoming multi-viewport feature will need them internally.
-// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
+// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
@@ -819,7 +819,7 @@ VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physic
}
else
{
- // Request several formats, the first found will be used
+ // Request several formats, the first found will be used
for (int request_i = 0; request_i < request_formats_count; request_i++)
for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)
if (avail_format[avail_i].format == request_formats[request_i] && avail_format[avail_i].colorSpace == request_color_space)
@@ -930,7 +930,7 @@ void ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(VkPhysicalDevice
wd->BackBufferCount = 0;
if (wd->RenderPass)
vkDestroyRenderPass(device, wd->RenderPass, allocator);
-
+
// If min image count was not specified, request different count of images dependent on selected present mode
if (min_image_count == 0)
min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode);
diff --git a/examples/imgui_impl_vulkan.h b/examples/imgui_impl_vulkan.h
index 099e5621..ec9eb54b 100644
--- a/examples/imgui_impl_vulkan.h
+++ b/examples/imgui_impl_vulkan.h
@@ -9,7 +9,7 @@
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
-// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
+// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
#pragma once
@@ -48,11 +48,11 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_InvalidateDeviceObjects();
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
//-------------------------------------------------------------------------
-// You probably do NOT need to use or care about those functions.
+// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
// 2) the multi-viewport / platform window implementation needs them internally.
-// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
+// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
// Your application/engine will likely already have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp
index 932bc211..7b60dd1b 100644
--- a/examples/imgui_impl_win32.cpp
+++ b/examples/imgui_impl_win32.cpp
@@ -5,9 +5,8 @@
// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
+// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
-// Missing features:
-// [ ] Platform: Gamepad support (best leaving it to user application to fill io.NavInputs[] with gamepad inputs from their source of choice).
#include "imgui.h"
#include "imgui_impl_win32.h"
@@ -15,11 +14,15 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include
+#include
#include
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
+// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
+// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
+// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
@@ -33,7 +36,7 @@
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
-// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
+// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
// Win32 Data
@@ -41,6 +44,8 @@ static HWND g_hWnd = 0;
static INT64 g_Time = 0;
static INT64 g_TicksPerSecond = 0;
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
+static bool g_HasGamepad = false;
+static bool g_WantUpdateHasGamepad = true;
static bool g_WantUpdateMonitors = true;
// Forward Declarations
@@ -135,21 +140,14 @@ static bool ImGui_ImplWin32_UpdateMouseCursor()
return true;
}
-// This code supports multiple OS Windows mapped into different ImGui viewports,
-// Because of that, it is a little more complicated than your typical single-viewport binding code.
-// A) In Single-viewport mode imgui needs:
-// - io.MousePos ............... mouse position, in client window coordinates (what you'd get from GetCursorPos+ScreenToClient() or from WM_MOUSEMOVE)
-// io.MousePos is (0,0) when the mouse is on the upper-left corner of the application window.
-// B) In Multi-viewport mode imgui needs: (when ImGuiConfigFlags_ViewportsEnable is set)
-// - io.MousePos ............... mouse position, in OS absolute coordinates (what you'd get from GetCursorPos(), or from WM_MOUSEMOVE+viewport->Pos).
-// io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor.
-// - io.MouseHoveredViewport ... [optional] viewport which mouse is hovering, with _VERY_ specific and strict conditions (Read comments next to io.MouseHoveredViewport. This is _NOT_ easy to provide in many high-level engine because of how we use the ImGuiViewportFlags_NoInputs flag)
+// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
+// Because of that, it is a little more complicated than your typical single-viewport binding code!
static void ImGui_ImplWin32_UpdateMousePos()
{
ImGuiIO& io = ImGui::GetIO();
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
- // (When multi-viewports are enabled, all imgui positions are same as OS positions.)
+ // (When multi-viewports are enabled, all imgui positions are same as OS positions)
if (io.WantSetMousePos)
{
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
@@ -161,28 +159,109 @@ static void ImGui_ImplWin32_UpdateMousePos()
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
io.MouseHoveredViewport = 0;
- // Set mouse position and viewport
- // (Note that ScreenToClient() and adding +viewport->Pos are mutually cancelling each others when we have multi-viewport enabled. In single-viewport mode, viewport->Pos will be zero)
- POINT pos;
- if (!::GetCursorPos(&pos))
+ // Set imgui mouse position
+ POINT mouse_screen_pos;
+ if (!::GetCursorPos(&mouse_screen_pos))
return;
- if (HWND focused_hwnd = ::GetActiveWindow())
- if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)focused_hwnd))
+ if (HWND focused_hwnd = ::GetForegroundWindow())
+ {
+ if (::IsChild(focused_hwnd, g_hWnd))
+ focused_hwnd = g_hWnd;
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
+ // This is the position you can get with GetCursorPos(). In theory adding viewport->Pos is also the reverse operation of doing ScreenToClient().
+ if (ImGui::FindViewportByPlatformHandle((void*)focused_hwnd) != NULL)
+ io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y);
+ }
+ else
{
- POINT client_pos = pos;
- ::ScreenToClient(focused_hwnd, &client_pos);
- io.MousePos = ImVec2(viewport->Pos.x + (float)client_pos.x, viewport->Pos.y + (float)client_pos.y);
+ // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window.)
+ // This is the position you can get with GetCursorPos() + ScreenToClient() or from WM_MOUSEMOVE.
+ if (focused_hwnd == g_hWnd)
+ {
+ POINT mouse_client_pos = mouse_screen_pos;
+ ::ScreenToClient(focused_hwnd, &mouse_client_pos);
+ io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y);
+ }
}
+ }
- // Our back-end can tell which window is under the mouse cursor (not every back-end can), so pass that info to imgui
- if (HWND hovered_hwnd = ::WindowFromPoint(pos))
+ // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
+ // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
+ // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
+ // - This is _regardless_ of whether another viewport is focused or being dragged from.
+ // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the
+ // rectangles and last focused time of every viewports it knows about. It will be unaware of foreign windows that may be sitting between or over your windows.
+ if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd))
- io.MouseHoveredViewport = viewport->ID;
+ if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated?
+ io.MouseHoveredViewport = viewport->ID;
+
+#if 0
+ POINT pos;
+ if (HWND active_window = ::GetForegroundWindow())
+ if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd))
+ if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos))
+ io.MousePos = ImVec2((float)pos.x, (float)pos.y);
+#endif
+}
+
+#ifdef _MSC_VER
+#pragma comment(lib, "xinput")
+#endif
+
+// Gamepad navigation mapping
+void ImGui_ImplWin32_UpdateGameControllers()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ memset(io.NavInputs, 0, sizeof(io.NavInputs));
+ if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
+ return;
+
+ // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
+ // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
+ if (g_WantUpdateHasGamepad)
+ {
+ XINPUT_CAPABILITIES caps;
+ g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
+ g_WantUpdateHasGamepad = false;
+ }
+
+ XINPUT_STATE xinput_state;
+ io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+ if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
+ {
+ const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
+ io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+
+ #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
+ #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
+ MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
+ MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
+ MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
+ MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
+ MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
+ MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
+ MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
+ MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
+ MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
+ MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
+ MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
+ MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
+ MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
+ MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
+ MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
+ MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
+ #undef MAP_BUTTON
+ #undef MAP_ANALOG
+ }
}
void ImGui_ImplWin32_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing)
RECT rect;
@@ -214,14 +293,20 @@ void ImGui_ImplWin32_NewFrame()
g_LastMouseCursor = mouse_cursor;
ImGui_ImplWin32_UpdateMouseCursor();
}
+
+ // Update game controllers (if available)
+ ImGui_ImplWin32_UpdateGameControllers();
}
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
#endif
+#ifndef DBT_DEVNODES_CHANGED
+#define DBT_DEVNODES_CHANGED 0x0007
+#endif
-// Process Win32 mouse/keyboard inputs.
+// Process Win32 mouse/keyboard inputs.
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
@@ -239,11 +324,13 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
+ case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
{
int button = 0;
- if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) button = 0;
- if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) button = 1;
- if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) button = 2;
+ if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
+ if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
+ if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
+ if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
::SetCapture(hwnd);
io.MouseDown[button] = true;
@@ -252,11 +339,13 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
+ case WM_XBUTTONUP:
{
int button = 0;
- if (msg == WM_LBUTTONUP) button = 0;
- if (msg == WM_RBUTTONUP) button = 1;
- if (msg == WM_MBUTTONUP) button = 2;
+ if (msg == WM_LBUTTONUP) { button = 0; }
+ if (msg == WM_RBUTTONUP) { button = 1; }
+ if (msg == WM_MBUTTONUP) { button = 2; }
+ if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
io.MouseDown[button] = false;
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
::ReleaseCapture();
@@ -287,6 +376,10 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
return 1;
return 0;
+ case WM_DEVICECHANGE:
+ if ((UINT)wParam == DBT_DEVNODES_CHANGED)
+ g_WantUpdateHasGamepad = true;
+ return 0;
case WM_DISPLAYCHANGE:
g_WantUpdateMonitors = true;
return 0;
@@ -323,6 +416,8 @@ typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_
#ifndef _DPI_AWARENESS_CONTEXTS_
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
+#endif
+#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
#endif
typedef HRESULT(WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib+dll, Windows 8.1
@@ -355,7 +450,7 @@ void ImGui_ImplWin32_EnableDpiAwareness()
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
{
UINT xdpi = 96, ydpi = 96;
- if (IsWindows8Point1OrGreater())
+ if (::IsWindows8Point1OrGreater())
{
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"))
@@ -378,13 +473,6 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
}
-float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2)
-{
- RECT viewport_rect = { (LONG)x1, (LONG)y1, (LONG)x2, (LONG)y2 };
- HMONITOR monitor = ::MonitorFromRect(&viewport_rect, MONITOR_DEFAULTTONEAREST);
- return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
-}
-
//--------------------------------------------------------------------------------------------------------
// IME (Input Method Editor) basic support for e.g. Asian language users
//--------------------------------------------------------------------------------------------------------
@@ -426,33 +514,41 @@ struct ImGuiViewportDataWin32
~ImGuiViewportDataWin32() { IM_ASSERT(Hwnd == NULL); }
};
+static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style)
+{
+ if (flags & ImGuiViewportFlags_NoDecoration)
+ *out_style = WS_POPUP;
+ else
+ *out_style = WS_OVERLAPPEDWINDOW;
+
+ if (flags & ImGuiViewportFlags_NoTaskBarIcon)
+ *out_ex_style = WS_EX_TOOLWINDOW;
+ else
+ *out_ex_style = WS_EX_APPWINDOW;
+
+ if (flags & ImGuiViewportFlags_TopMost)
+ *out_ex_style |= WS_EX_TOPMOST;
+}
+
static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
{
ImGuiViewportDataWin32* data = IM_NEW(ImGuiViewportDataWin32)();
viewport->PlatformUserData = data;
- bool no_decoration = (viewport->Flags & ImGuiViewportFlags_NoDecoration) != 0;
- bool no_task_bar_icon = (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) != 0;
- if (no_decoration)
- {
- data->DwStyle = WS_POPUP;
- data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW;
- }
- else
- {
- data->DwStyle = WS_OVERLAPPEDWINDOW;
- data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW;
- }
- if (viewport->Flags & ImGuiViewportFlags_TopMost)
- data->DwExStyle |= WS_EX_TOPMOST;
+ // Select style and parent window
+ ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &data->DwStyle, &data->DwExStyle);
+ HWND parent_window = NULL;
+ if (viewport->ParentViewportId != 0)
+ if (ImGuiViewport* parent_viewport = ImGui::FindViewportByID(viewport->ParentViewportId))
+ parent_window = (HWND)parent_viewport->PlatformHandle;
// Create window
RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle);
data->Hwnd = ::CreateWindowEx(
- data->DwExStyle, _T("ImGui Platform"), _T("No Title Yet"), data->DwStyle, // Style, class name, window name
- rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
- g_hWnd, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param
+ data->DwExStyle, _T("ImGui Platform"), _T("Untitled"), data->DwStyle, // Style, class name, window name
+ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
+ parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param
data->HwndOwned = true;
viewport->PlatformRequestResize = false;
viewport->PlatformHandle = data->Hwnd;
@@ -486,6 +582,31 @@ static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
::ShowWindow(data->Hwnd, SW_SHOW);
}
+static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport)
+{
+ // (Optional) Update Win32 style if it changed _after_ creation.
+ // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
+ ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
+ IM_ASSERT(data->Hwnd != 0);
+ DWORD new_style;
+ DWORD new_ex_style;
+ ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style);
+
+ // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
+ if (data->DwStyle != new_style || data->DwExStyle != new_ex_style)
+ {
+ data->DwStyle = new_style;
+ data->DwExStyle = new_ex_style;
+ ::SetWindowLong(data->Hwnd, GWL_STYLE, data->DwStyle);
+ ::SetWindowLong(data->Hwnd, GWL_EXSTYLE, data->DwExStyle);
+ RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
+ ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen
+ ::SetWindowPos(data->Hwnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ ::ShowWindow(data->Hwnd, SW_SHOWNA); // This is necessary when we alter the style
+ viewport->PlatformRequestMove = viewport->PlatformRequestResize = true;
+ }
+}
+
static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
{
ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
@@ -535,7 +656,7 @@ static bool ImGui_ImplWin32_GetWindowFocus(ImGuiViewport* viewport)
{
ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
IM_ASSERT(data->Hwnd != 0);
- return ::GetActiveWindow() == data->Hwnd;
+ return ::GetForegroundWindow() == data->Hwnd;
}
static bool ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport* viewport)
@@ -578,13 +699,8 @@ static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport)
{
ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
- if (data && data->Hwnd)
- return ImGui_ImplWin32_GetDpiScaleForHwnd(data->Hwnd);
-
- // The first frame a viewport is created we don't have a window yet
- return ImGui_ImplWin32_GetDpiScaleForRect(
- (int)(viewport->Pos.x), (int)(viewport->Pos.y),
- (int)(viewport->Pos.x + viewport->Size.x), (int)(viewport->Pos.y + viewport->Size.y));
+ IM_ASSERT(data->Hwnd != 0);
+ return ImGui_ImplWin32_GetDpiScaleForHwnd(data->Hwnd);
}
// FIXME-DPI: Testing DPI related ideas
@@ -621,6 +737,10 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd,
case WM_SIZE:
viewport->PlatformRequestResize = true;
break;
+ case WM_MOUSEACTIVATE:
+ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick)
+ return MA_NOACTIVATE;
+ break;
case WM_NCHITTEST:
// Let mouse pass-through the window. This will allow the back-end to set io.MouseHoveredViewport properly (which is OPTIONAL).
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
@@ -695,7 +815,8 @@ static void ImGui_ImplWin32_InitPlatformInterface()
platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized;
platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle;
platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha;
- platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale;
+ platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
+ platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
#if HAS_WIN32_IME
platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
diff --git a/examples/imgui_impl_win32.h b/examples/imgui_impl_win32.h
index 5f163152..f621f7ac 100644
--- a/examples/imgui_impl_win32.h
+++ b/examples/imgui_impl_win32.h
@@ -5,9 +5,8 @@
// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
+// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
-// Missing features:
-// [ ] Platform: Gamepad support (best leaving it to user application to fill io.NavInputs[] with gamepad inputs from their source of choice).
#pragma once
@@ -16,10 +15,9 @@ IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
// DPI-related helpers (which run and compile without requiring 8.1 or 10, neither Windows version, neither associated SDK)
-IMGUI_API void ImGui_ImplWin32_EnableDpiAwareness();
-IMGUI_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
-IMGUI_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
-IMGUI_API float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2);
+IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
+IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
+IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
// Handler for Win32 messages, update mouse/keyboard data.
// You may or not need this for your implementation, but it can serve as reference for handling inputs.
diff --git a/imgui.cpp b/imgui.cpp
index 3c9fcff6..598a41f5 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.67 WIP
+// dear imgui, v1.68 WIP
// (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
@@ -7,9 +7,12 @@
// Releases change-log at https://github.com/ocornut/imgui/releases
// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started
// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
+
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
+// See LICENSE.txt for copyright and licensing details (standard MIT License).
// This library is free but I need your support to sustain development and maintenance.
-// If you work for a company, please consider financial support, see README. For individuals: https://www.patreon.com/imgui
+// Businesses: you can support continued maintenance and development via support contracts or sponsoring, see docs/README.
+// Individuals: you can support continued maintenance and development via donations or Patreon https://www.patreon.com/imgui.
// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
@@ -26,28 +29,30 @@ DOCUMENTATION
- MISSION STATEMENT
- END-USER GUIDE
- PROGRAMMER GUIDE (read me!)
- - Read first
- - How to update to a newer version of Dear ImGui
- - Getting started with integrating Dear ImGui in your code/engine
- - This is how a simple application may look like (2 variations)
- - This is how a simple rendering function may look like
- - Using gamepad/keyboard navigation controls
+ - Read first.
+ - How to update to a newer version of Dear ImGui.
+ - Getting started with integrating Dear ImGui in your code/engine.
+ - This is how a simple application may look like (2 variations).
+ - This is how a simple rendering function may look like.
+ - Using gamepad/keyboard navigation controls.
- API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
- How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- How can I display an image? What is ImTextureID, how does it works?
- - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack.
- - How can I use my own math types instead of ImVec2/ImVec4?
+ - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
+ - How can I use my own math types instead of ImVec2/ImVec4?
- How can I load a different font than the default?
- How can I easily use icons in my application?
- How can I load multiple fonts?
- How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
+ - How can I interact with standard C++ types (such as std::string and std::vector)?
- How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
+ - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad)
- I integrated Dear ImGui in my engine and the text or lines are blurry..
- I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
- How can I help?
-CODE
+CODE
(search for "[SECTION]" in the code to find them)
// [SECTION] FORWARD DECLARATIONS
@@ -85,19 +90,19 @@ CODE
MISSION STATEMENT
=================
- - Easy to use to create code-driven and data-driven tools
- - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
- - Easy to hack and improve
- - Minimize screen real-estate usage
- - Minimize setup and maintenance
- - Minimize state storage on user side
- - Portable, minimize dependencies, run on target (consoles, phones, etc.)
- - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,
- opening a tree node for the first time, etc. but a typical frame should not allocate anything)
+ - Easy to use to create code-driven and data-driven tools.
+ - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
+ - Easy to hack and improve.
+ - Minimize screen real-estate usage.
+ - Minimize setup and maintenance.
+ - Minimize state storage on user side.
+ - Portable, minimize dependencies, run on target (consoles, phones, etc.).
+ - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,.
+ opening a tree node for the first time, etc. but a typical frame should not allocate anything).
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
+ - Doesn't look fancy, doesn't animate.
+ - Limited layout features, intricate layouts are typically crafted in code.
END-USER GUIDE
@@ -127,16 +132,29 @@ CODE
PROGRAMMER GUIDE
================
- READ FIRST
+ READ FIRST:
- Read the FAQ below this section!
- Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction
or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs.
- Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
- - You can learn about immediate-mode GUI principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
- See README.md for more links describing the IMGUI paradigm. Dear ImGui is an implementation of the IMGUI paradigm.
-
- HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
+ - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
+ - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
+ You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links docs/README.md.
+ - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
+ For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI,
+ where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
+ - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
+ - This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
+ - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
+ If you get an assert, read the messages and comments around the assert.
+ - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace.
+ - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
+ See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
+ However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
+ - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
+
+ HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI:
- Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
- Or maintain your own branch where you have imconfig.h modified.
@@ -146,7 +164,7 @@ CODE
likely be a comment about it. Please report any issue to the GitHub page!
- Try to keep your copy of dear imgui reasonably up to date.
- GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
+ GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE:
- Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
- Add the Dear ImGui source files to your projects or using your preferred build system.
@@ -159,8 +177,8 @@ CODE
- Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
- If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.
- HOW A SIMPLE APPLICATION MAY LOOK LIKE
- EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder)
+ HOW A SIMPLE APPLICATION MAY LOOK LIKE:
+ EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder).
// Application init: create a dear imgui context, setup some options, load fonts
ImGui::CreateContext();
@@ -189,14 +207,14 @@ CODE
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
g_pSwapChain->Present(1, 0);
}
-
+
// Shutdown
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
- HOW A SIMPLE APPLICATION MAY LOOK LIKE
- EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE
+ HOW A SIMPLE APPLICATION MAY LOOK LIKE:
+ EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE.
// Application init: create a dear imgui context, setup some options, load fonts
ImGui::CreateContext();
@@ -250,16 +268,17 @@ CODE
// Shutdown
ImGui::DestroyContext();
- HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
+ HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE:
void void MyImGuiRenderFunction(ImDrawData* draw_data)
{
// TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
- // TODO: Setup viewport using draw_data->DisplaySize
+ // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
// TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
// TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
@@ -280,7 +299,7 @@ CODE
// (some elements visible outside their bounds) but you can fix that once everything else works!
// - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize)
// In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize.
- // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github),
+ // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github),
// always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
// - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
ImVec2 pos = draw_data->DisplayPos;
@@ -297,13 +316,13 @@ CODE
- The examples/ folders contains many actual implementation of the pseudo-codes above.
- When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
- They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs
+ They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs
from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information.
- Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues!
USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
- - The gamepad/keyboard navigation is fairly functional and keeps being improved.
+ - The gamepad/keyboard navigation is fairly functional and keeps being improved.
- Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse!
- You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
- The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
@@ -348,19 +367,22 @@ CODE
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
(Viewport Branch)
- - 2018/XX/XX (1.XX) - examples: the examples imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.)
- when adopting new bindings follow the code in examples/ to know which functions to call.
- 2018/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
- reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
- - likewise io.MousePos and GetMousePos() will use OS coordinates coordinates.
+ - likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2018/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
- - 2018/XX/XX (1.XX) - removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (it was used to clip within the DisplayMin..DisplayMax range, I don't know of anyone using it)
+ - 2018/XX/XX (1.XX) - removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were used to clip within the (0,0)..DisplaySize range, I don't know of anyone using it)
+
- - 2018/10/12 (1.66) - Renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
+ - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
+ - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete).
+ - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects.
+ - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
+ - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
- 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
- - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.
+ - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.
If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
- 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
- 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp.
@@ -369,12 +391,15 @@ CODE
- 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).
- 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
- 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
- - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges to enable the feature.
+ - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature.
- 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
- 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
- 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
+ - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.).
+ old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant.
+ when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call.
- 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
- - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
+ - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
- 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.
@@ -421,6 +446,7 @@ CODE
removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
- 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
- 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
+ - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete).
- 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
- 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
- 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
@@ -478,7 +504,7 @@ CODE
- the signature of the io.RenderDrawListsFn handler has changed!
old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
- argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
+ parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
- each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.
@@ -511,9 +537,9 @@ CODE
- 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
- 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
(1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
- font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>
- became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier;
- you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
+ font init: { const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>; }
+ became: { unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; }
+ you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
it is now recommended that you sample the font texture with bilinear interpolation.
(1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
(1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
@@ -553,7 +579,7 @@ CODE
A: Short explanation:
- You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures.
- Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value.
- - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
+ - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.
Long explanation:
@@ -561,10 +587,10 @@ CODE
At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code
to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.).
- Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API.
- We carry the information to identify a "texture" in the ImTextureID type.
+ We carry the information to identify a "texture" in the ImTextureID type.
ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice.
Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function.
- - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying
+ - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying
an image from the end-user perspective. This is what the _examples_ rendering functions are using:
OpenGL: ImTextureID = GLuint (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp)
@@ -572,13 +598,13 @@ CODE
DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp)
DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp)
- For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID.
- Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure
+ For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID.
+ Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure
tying together both the texture and information about its format and how to read it.
- If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about
the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase
is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them.
- If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID
+ If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID
representation suggested by the example bindings is probably the best choice.
(Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer)
@@ -586,7 +612,7 @@ CODE
// Cast our texture type to ImTextureID / void*
MyTexture* texture = g_CoffeeTableTexture;
- ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height));
+ ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height));
The renderer function called after ImGui::Render() will receive that same value that the user code passed:
@@ -619,7 +645,7 @@ CODE
// Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it:
ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height));
- C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa.
+ C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa.
Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTexture / void*.
Examples:
@@ -635,13 +661,13 @@ CODE
Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
- Q: How can I have multiple widgets with the same label or without a label?
+ Q: How can I have multiple widgets with the same label or with an empty label?
Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
Elements that are typically not clickable (such as calls to the Text functions) don't need an ID.
- Interactive widgets (such as calls to Button buttons) need a unique ID.
+ Interactive widgets (such as calls to Button buttons) need a unique ID.
Unique ID are used internally to track active widgets and occasionally associate state to widgets.
Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.
@@ -657,6 +683,9 @@ CODE
Begin("MyWindow");
Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK")
End();
+ Begin("MyOtherWindow");
+ Button("OK"); // Label = "OK", ID = hash of ("MyOtherWindow", "OK")
+ End();
- If you have a same ID twice in the same location, you'll have a conflict:
@@ -685,8 +714,8 @@ CODE
you to animate labels. For example you may want to include varying information in a window title bar,
but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
- Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "ID")
- Button("World###ID"); // Label = "World", ID = hash of (..., "ID") // Same as above, even though the label looks different
+ Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID")
+ Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same as above, even though the label looks different
sprintf(buf, "My game (%f FPS)###MyGame", fps);
Begin(buf); // Variable title, ID = hash of "MyGame"
@@ -696,47 +725,48 @@ CODE
within the same window. This is the most convenient way of distinguishing ID when iterating and
creating many UI elements programmatically.
You can push a pointer, a string or an integer value into the ID stack.
- Remember that ID are formed from the concatenation of _everything_ in the ID stack!
+ Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack.
+ At each level of the stack we store the seed used for items at this level of the ID stack.
- Begin("Window");
+ Begin("Window");
for (int i = 0; i < 100; i++)
{
- PushID(i); // Push i to the id tack
- Button("Click"); // Label = "Click", ID = Hash of ("Window", i, "Click")
+ PushID(i); // Push i to the id tack
+ Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click")
PopID();
}
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj);
- Button("Click"); // Label = "Click", ID = Hash of ("Window", obj pointer, "Click")
+ Button("Click"); // Label = "Click", ID = hash of ("Window", obj pointer, "Click")
PopID();
}
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj->Name);
- Button("Click"); // Label = "Click", ID = Hash of ("Window", obj->Name, "Click")
+ Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click")
PopID();
}
End();
- - More example showing that you can stack multiple prefixes into the ID stack:
+ - You can stack multiple prefixes into the ID stack:
- Button("Click"); // Label = "Click", ID = hash of (..., "Click")
+ Button("Click"); // Label = "Click", ID = hash of (..., "Click")
PushID("node");
- Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
+ Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
PushID(my_ptr);
- Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click")
+ Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click")
PopID();
PopID();
- Tree nodes implicitly creates a scope for you by calling PushID().
- Button("Click"); // Label = "Click", ID = hash of (..., "Click")
- if (TreeNode("node"))
+ Button("Click"); // Label = "Click", ID = hash of (..., "Click")
+ if (TreeNode("node")) // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag)
{
- Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
+ Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
TreePop();
}
@@ -747,7 +777,7 @@ CODE
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
node open/closed state differently. See what makes more sense in your situation!
- Q: How can I use my own math types instead of ImVec2/ImVec4?
+ Q: How can I use my own math types instead of ImVec2/ImVec4?
A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions.
This way you'll be able to use your own types everywhere, e.g. passsing glm::vec2 to ImGui functions instead of ImVec2.
@@ -756,7 +786,8 @@ CODE
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
- Default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code.
+ Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code.
+ (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.)
(Read the 'misc/fonts/README.txt' file for more details about font loading.)
New programmers: remember that in C/C++ and most programming languages if you want to use a
@@ -767,7 +798,8 @@ CODE
Q: How can I easily use icons in my application?
A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you
- main font. Then you can refer to icons within your strings.
+ main font. Then you can refer to icons within your strings.
+ You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment.
(Read the 'misc/fonts/README.txt' file for more details about icons font loading.)
Q: How can I load multiple fonts?
@@ -806,7 +838,7 @@ CODE
// Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need)
ImVector ranges;
- ImFontAtlas::GlyphRangesBuilder builder;
+ ImFontGlyphRangesBuilder builder;
builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
builder.AddChar(0x7262); // Add a specific character
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
@@ -818,13 +850,35 @@ CODE
(such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
- Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter().
- The applications in examples/ are doing that.
+ Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter().
+ The applications in examples/ are doing that.
Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode).
You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state.
- Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for
+ Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for
the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly.
+ Q: How can I interact with standard C++ types (such as std::string and std::vector)?
+ A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers),
+ and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use
+ any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases.
+ - To use ImGui::InputText() with a std::string or any resizable string class, see misc/cpp/imgui_stdlib.h.
+ - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API
+ lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API.
+ Prefer using them over the old and awkward Combo()/ListBox() api.
+ - Generally for most high-level types you should be able to access the underlying data type.
+ You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code).
+ - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass
+ to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application.
+ Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances.
+ Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those
+ are not configurable and not the same across implementations.
+ - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount
+ of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern
+ is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead.
+ One possible implementation of a helper to facilitate printf-style building of strings: https://github.com/ocornut/Str
+ This is a small helper where you can instance strings with configurable local buffers length. Many game engines will
+ provide similar or better string helpers.
+
Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
A: - You can create a dummy window. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags.
(The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse)
@@ -833,6 +887,21 @@ CODE
- You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData,
and then call your rendered code with your own ImDrawList or ImDrawData data.
+ Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
+ A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls".
+ (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad)
+ - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy)
+ This is the preferred solution for developer productivity.
+ In particular, the "micro-synergy-client" repository (https://github.com/symless/micro-synergy-client) has simple
+ and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect
+ to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer.
+ Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols.
+ - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends
+ the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine.
+ - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate
+ for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing
+ for screen real-estate and precision.
+
Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
@@ -842,10 +911,12 @@ CODE
Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
Q: How can I help?
- A: - If you are experienced with Dear ImGui and C++, look at the github issues, or docs/TODO.txt and see how you want/can help!
- - Convince your company to sponsor/fund development! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README.
+ A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
+ and see how you want to help and can help!
+ - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui.
+ - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README.
- Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
- You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers.
+ You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1902). Visuals are ideal as they inspire other programmers.
But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
- If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately).
@@ -898,7 +969,13 @@ CODE
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
#pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
-#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
+#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
+#endif
+#if __has_warning("-Wdouble-promotion")
+#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
+#endif
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
@@ -916,9 +993,9 @@ CODE
static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
-// Window resizing from edges (when io.ConfigResizeWindowsFromEdges = true)
-static const float RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
-static const float RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
+// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end)
+static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
+static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
// Docking
static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For use with io.ConfigDockingTransparentPayload. Apply to Viewport _or_ WindowBg in host viewport.
@@ -969,11 +1046,14 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
static void UpdateMouseInputs();
static void UpdateMouseWheel();
static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
+static void RenderOuterBorders(ImGuiWindow* window);
+static void EndFrameDrawDimmedBackgrounds();
// Viewports
-const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHash("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
+const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
static ImGuiViewportP* AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& platform_pos, const ImVec2& size, ImGuiViewportFlags flags);
-static void UpdateViewports();
+static void UpdateViewportsNewFrame();
+static void UpdateViewportsEndFrame();
static void UpdateSelectWindowViewport(ImGuiWindow* window);
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
static void SetCurrentViewport(ImGuiWindow* window, ImGuiViewportP* viewport);
@@ -983,24 +1063,24 @@ static int FindPlatformMonitorForRect(const ImRect& r);
}
-// Test engine hooks (imgui-test)
-//#define IMGUI_ENABLE_TEST_ENGINE_HOOKS
-#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS
-extern void ImGuiTestEngineHook_PreNewFrame();
-extern void ImGuiTestEngineHook_PostNewFrame();
-extern void ImGuiTestEngineHook_ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg);
-#endif
-
//-----------------------------------------------------------------------------
// [SECTION] CONTEXT AND MEMORY ALLOCATORS
//-----------------------------------------------------------------------------
// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
-// CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
-// If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file.
-// ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can:
-// - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
-// - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts)
+// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
+// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call
+// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading.
+// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into.
+// 2) Important: Dear ImGui functions are not thread-safe because of this pointer.
+// If you want thread-safety to allow N threads to access N different contexts, you can:
+// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h:
+// struct ImGuiContext;
+// extern thread_local ImGuiContext* MyImGuiTLS;
+// #define GImGui MyImGuiTLS
+// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
+// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
+// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace.
#ifndef GImGui
ImGuiContext* GImGui = NULL;
#endif
@@ -1009,11 +1089,11 @@ ImGuiContext* GImGui = NULL;
// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
-static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); }
-static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); }
+static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
+static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
#else
-static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; }
-static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); }
+static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
+static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
#endif
static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
@@ -1051,7 +1131,7 @@ ImGuiStyle::ImGuiStyle()
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
TabBorderSize = 0.0f; // Thickness of border around tabs.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
- DisplayWindowPadding = ImVec2(20,20); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
+ DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
@@ -1115,19 +1195,32 @@ ImGuiIO::ImGuiIO()
FontAllowUserScaling = false;
DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
- // Miscellaneous configuration options
+ // Docking options (when ImGuiConfigFlags_DockingEnable is set)
+ ConfigDockingNoSplit = false;
ConfigDockingWithShift = false;
+ ConfigDockingTabBarOnSingleWindows = false;
ConfigDockingTransparentPayload = false;
+
+ // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set)
+ ConfigViewportsNoAutoMerge = false;
+ ConfigViewportsNoTaskBarIcon = false;
+ ConfigViewportsNoDecoration = true;
+ ConfigViewportsNoParent = false;
+
+ // Miscellaneous options
+ MouseDrawCursor = false;
#ifdef __APPLE__
ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
#else
ConfigMacOSXBehaviors = false;
#endif
ConfigInputTextCursorBlink = true;
- ConfigResizeWindowsFromEdges = true;
+ ConfigWindowsResizeFromEdges = true;
+ ConfigWindowsMoveFromTitleBarOnly = false;
// Platform Functions
BackendPlatformName = BackendRendererName = NULL;
+ BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
ClipboardUserData = NULL;
@@ -1150,22 +1243,23 @@ ImGuiIO::ImGuiIO()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
void ImGuiIO::AddInputCharacter(ImWchar c)
{
- const int n = ImStrlenW(InputCharacters);
- if (n + 1 < IM_ARRAYSIZE(InputCharacters))
+ InputQueueCharacters.push_back(c);
+}
+
+void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
+{
+ while (*utf8_chars != 0)
{
- InputCharacters[n] = c;
- InputCharacters[n+1] = '\0';
+ unsigned int c = 0;
+ utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
+ if (c > 0 && c <= 0xFFFF)
+ InputQueueCharacters.push_back((ImWchar)c);
}
}
-void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
+void ImGuiIO::ClearInputCharacters()
{
- // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
- const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
- ImWchar wchars[wchars_buf_len];
- ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
- for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
- AddInputCharacter(wchars[i]);
+ InputQueueCharacters.resize(0);
}
//-----------------------------------------------------------------------------
@@ -1220,6 +1314,7 @@ ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c,
return proj_ca;
}
+// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
int ImStricmp(const char* str1, const char* str2)
{
int d;
@@ -1236,16 +1331,32 @@ int ImStrnicmp(const char* str1, const char* str2, size_t count)
void ImStrncpy(char* dst, const char* src, size_t count)
{
- if (count < 1) return;
- strncpy(dst, src, count);
- dst[count-1] = 0;
+ if (count < 1)
+ return;
+ if (count > 1)
+ strncpy(dst, src, count - 1);
+ dst[count - 1] = 0;
}
-char* ImStrdup(const char *str)
+char* ImStrdup(const char* str)
{
- size_t len = strlen(str) + 1;
- void* buf = ImGui::MemAlloc(len);
- return (char*)memcpy(buf, (const void*)str, len);
+ size_t len = strlen(str);
+ void* buf = ImGui::MemAlloc(len + 1);
+ return (char*)memcpy(buf, (const void*)str, len + 1);
+}
+
+char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
+{
+ size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
+ size_t src_size = strlen(src) + 1;
+ if (dst_buf_size < src_size)
+ {
+ ImGui::MemFree(dst);
+ dst = (char*)ImGui::MemAlloc(src_size);
+ if (p_dst_size)
+ *p_dst_size = src_size;
+ }
+ return (char*)memcpy(dst, (const void*)src, src_size);
}
const char* ImStrchrRange(const char* str, const char* str_end, char c)
@@ -1326,6 +1437,12 @@ const char* ImStrSkipBlank(const char* str)
// B) When buf==NULL vsnprintf() will return the output size.
#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
+//#define IMGUI_USE_STB_SPRINTF
+#ifdef IMGUI_USE_STB_SPRINTF
+#define STB_SPRINTF_IMPLEMENTATION
+#include "imstb_sprintf.h"
+#endif
+
#if defined(_MSC_VER) && !defined(vsnprintf)
#define vsnprintf _vsnprintf
#endif
@@ -1334,7 +1451,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
+#ifdef IMGUI_USE_STB_SPRINTF
+ int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
+#else
int w = vsnprintf(buf, buf_size, fmt, args);
+#endif
va_end(args);
if (buf == NULL)
return w;
@@ -1346,7 +1467,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
{
+#ifdef IMGUI_USE_STB_SPRINTF
+ int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
+#else
int w = vsnprintf(buf, buf_size, fmt, args);
+#endif
if (buf == NULL)
return w;
if (w == -1 || w >= (int)buf_size)
@@ -1356,43 +1481,69 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
}
#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
-// Pass data_size==0 for zero-terminated strings
+// CRC32 needs a 1KB lookup table (not cache friendly)
+// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
+// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
+static const ImU32 GCrc32LookupTable[256] =
+{
+ 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
+ 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
+ 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
+ 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
+ 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
+ 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
+ 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
+ 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
+ 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
+ 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
+ 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
+ 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
+ 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
+ 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
+ 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
+ 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
+};
+
+// Known size hash
+// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
-ImU32 ImHash(const void* data, int data_size, ImU32 seed)
+ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed)
{
- static ImU32 crc32_lut[256] = { 0 };
- if (!crc32_lut[1])
- {
- const ImU32 polynomial = 0xEDB88320;
- for (ImU32 i = 0; i < 256; i++)
- {
- ImU32 crc = i;
- for (ImU32 j = 0; j < 8; j++)
- crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
- crc32_lut[i] = crc;
- }
- }
+ ImU32 crc = ~seed;
+ const unsigned char* data = (const unsigned char*)data_p;
+ const ImU32* crc32_lut = GCrc32LookupTable;
+ while (data_size-- != 0)
+ crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
+ return ~crc;
+}
+// Zero-terminated string hash, with support for ### to reset back to seed value
+// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
+// Because this syntax is rarely used we are optimizing for the common case.
+// - If we reach ### in the string we discard the hash so far and reset to the seed.
+// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
+// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
+ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed)
+{
seed = ~seed;
ImU32 crc = seed;
- const unsigned char* current = (const unsigned char*)data;
-
- if (data_size > 0)
+ const unsigned char* src = (const unsigned char*)data;
+ const ImU32* crc32_lut = GCrc32LookupTable;
+ if (data_size != 0)
{
- // Known size
- while (data_size--)
- crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
+ while (data_size-- != 0)
+ {
+ unsigned char c = *src++;
+ if (c == '#' && src[0] == '#' && src[1] == '#')
+ crc = seed;
+ crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
+ }
}
else
{
- // Zero-terminated string
- while (unsigned char c = *current++)
+ while (unsigned char c = *src++)
{
- // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
- // Because this syntax is rarely used we are optimizing for the common case.
- // - If we reach ### in the string we discard the hash so far and reset to the seed.
- // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
- if (c == '#' && current[0] == '#' && current[1] == '#')
+ if (c == '#' && src[0] == '#' && src[1] == '#')
crc = seed;
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
}
@@ -1755,15 +1906,15 @@ ImU32 ImGui::GetColorU32(ImU32 col)
//-----------------------------------------------------------------------------
// std::lower_bound but without the bullshit
-static ImVector::iterator LowerBound(ImVector& data, ImGuiID key)
+static ImGuiStorage::Pair* LowerBound(ImVector& data, ImGuiID key)
{
- ImVector::iterator first = data.begin();
- ImVector::iterator last = data.end();
+ ImGuiStorage::Pair* first = data.Data;
+ ImGuiStorage::Pair* last = data.Data + data.Size;
size_t count = (size_t)(last - first);
while (count > 0)
{
size_t count2 = count >> 1;
- ImVector::iterator mid = first + count2;
+ ImGuiStorage::Pair* mid = first + count2;
if (mid->key < key)
{
first = ++mid;
@@ -1796,7 +1947,7 @@ void ImGuiStorage::BuildSortByKey()
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
{
- ImVector::iterator it = LowerBound(const_cast&>(Data), key);
+ ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key);
if (it == Data.end() || it->key != key)
return default_val;
return it->val_i;
@@ -1809,7 +1960,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
{
- ImVector::iterator it = LowerBound(const_cast&>(Data), key);
+ ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key);
if (it == Data.end() || it->key != key)
return default_val;
return it->val_f;
@@ -1817,7 +1968,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
{
- ImVector::iterator it = LowerBound(const_cast&>(Data), key);
+ ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key);
if (it == Data.end() || it->key != key)
return NULL;
return it->val_p;
@@ -1826,7 +1977,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
{
- ImVector::iterator it = LowerBound(Data, key);
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
it = Data.insert(it, Pair(key, default_val));
return &it->val_i;
@@ -1839,7 +1990,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
{
- ImVector::iterator it = LowerBound(Data, key);
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
it = Data.insert(it, Pair(key, default_val));
return &it->val_f;
@@ -1847,7 +1998,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
{
- ImVector::iterator it = LowerBound(Data, key);
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
it = Data.insert(it, Pair(key, default_val));
return &it->val_p;
@@ -1856,7 +2007,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
void ImGuiStorage::SetInt(ImGuiID key, int val)
{
- ImVector::iterator it = LowerBound(Data, key);
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
Data.insert(it, Pair(key, val));
@@ -1872,7 +2023,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val)
void ImGuiStorage::SetFloat(ImGuiID key, float val)
{
- ImVector::iterator it = LowerBound(Data, key);
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
Data.insert(it, Pair(key, val));
@@ -1883,7 +2034,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val)
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
{
- ImVector::iterator it = LowerBound(Data, key);
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
Data.insert(it, Pair(key, val));
@@ -2018,6 +2169,32 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
char ImGuiTextBuffer::EmptyString[1] = { 0 };
+void ImGuiTextBuffer::append(const char* str, const char* str_end)
+{
+ int len = str_end ? (int)(str_end - str) : (int)strlen(str);
+
+ // Add zero-terminator the first time
+ const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
+ const int needed_sz = write_off + len;
+ if (write_off + len >= Buf.Capacity)
+ {
+ int new_capacity = Buf.Capacity * 2;
+ Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
+ }
+
+ Buf.resize(needed_sz);
+ memcpy(&Buf[write_off - 1], str, (size_t)len);
+ Buf[write_off - 1 + len] = 0;
+}
+
+void ImGuiTextBuffer::appendf(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ appendfv(fmt, args);
+ va_end(args);
+}
+
// Helper: Text buffer for logging/accumulating text
void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
{
@@ -2036,8 +2213,8 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
const int needed_sz = write_off + len;
if (write_off + len >= Buf.Capacity)
{
- int double_capacity = Buf.Capacity * 2;
- Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
+ int new_capacity = Buf.Capacity * 2;
+ Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
}
Buf.resize(needed_sz);
@@ -2045,14 +2222,6 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
va_end(args_copy);
}
-void ImGuiTextBuffer::appendf(const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- appendfv(fmt, args);
- va_end(args);
-}
-
//-----------------------------------------------------------------------------
// [SECTION] ImGuiListClipper
// This is currently not as flexible/powerful as it should be, needs some rework (see TODO)
@@ -2371,9 +2540,9 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
: DrawListInst(&context->DrawListSharedData)
{
Name = ImStrdup(name);
- ID = ImHash(name, 0);
+ ID = ImHashStr(name, 0);
IDStack.push_back(ID);
- Flags = FlagsPreviousFrame = 0;
+ Flags = FlagsPreviousFrame = ImGuiWindowFlags_None;
Viewport = NULL;
ViewportId = 0;
ViewportAllowPlatformMonitorExtend = -1;
@@ -2384,6 +2553,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
WindowPadding = ImVec2(0.0f, 0.0f);
WindowRounding = 0.0f;
WindowBorderSize = 0.0f;
+ NameBufLen = (int)strlen(name) + 1;
MoveId = GetID("#MOVE");
ChildId = 0;
Scroll = ImVec2(0.0f, 0.0f);
@@ -2400,6 +2570,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
Appearing = false;
Hidden = false;
HasCloseButton = false;
+ ResizeBorderHeld = -1;
BeginCount = 0;
BeginOrderWithinParent = -1;
BeginOrderWithinContext = -1;
@@ -2451,7 +2622,7 @@ ImGuiWindow::~ImGuiWindow()
ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
- ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
+ ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
ImGui::KeepAliveID(id);
return id;
}
@@ -2459,7 +2630,7 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
ImGuiID ImGuiWindow::GetID(const void* ptr)
{
ImGuiID seed = IDStack.back();
- ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
+ ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
ImGui::KeepAliveID(id);
return id;
}
@@ -2467,13 +2638,13 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
- return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
+ return ImHashStr(str, str_end ? (str_end - str) : 0, seed);
}
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
{
ImGuiID seed = IDStack.back();
- return ImHash(&ptr, sizeof(void*), seed);
+ return ImHashData(&ptr, sizeof(void*), seed);
}
// This is only used in rare/specific situations to manufacture an ID out of nowhere.
@@ -2481,7 +2652,7 @@ ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
{
ImGuiID seed = IDStack.back();
const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) };
- ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed);
+ ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
ImGui::KeepAliveID(id);
return id;
}
@@ -2529,6 +2700,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
}
g.ActiveId = id;
g.ActiveIdAllowNavDirFlags = 0;
+ g.ActiveIdBlockNavInputFlags = 0;
g.ActiveIdAllowOverlap = false;
g.ActiveIdWindow = window;
if (id)
@@ -2538,13 +2710,14 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
}
}
+// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring.
void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(id != 0);
// Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it.
- const int nav_layer = window->DC.NavLayerCurrent;
+ const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
if (g.NavWindow != window)
g.NavInitRequest = false;
g.NavId = id;
@@ -2593,9 +2766,9 @@ void ImGui::MarkItemEdited(ImGuiID id)
{
// This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
// ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data.
- (void)id; // Avoid unused variable warnings when asserts are compiled out.
ImGuiContext& g = *GImGui;
IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
+ IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.ActiveIdHasBeenEdited = true;
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
@@ -2639,7 +2812,8 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
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.Indent.x + window->DC.ColumnsOffset.x), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
+ window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ window->DC.CursorPos.y = (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 - g.Style.ItemSpacing.y);
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
@@ -2663,10 +2837,6 @@ void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
{
-#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS
- ImGuiTestEngineHook_ItemAdd(bb, id, nav_bb_arg);
-#endif
-
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -2686,7 +2856,12 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
window->DC.LastItemId = id;
window->DC.LastItemRect = bb;
- window->DC.LastItemStatusFlags = 0;
+ window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
+
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ if (id != 0)
+ ImGuiTestEngineHook_ItemAdd(&g, nav_bb_arg ? *nav_bb_arg : bb, id);
+#endif
// Clipping test
const bool is_clipped = IsClippedEx(bb, id, false);
@@ -2844,7 +3019,7 @@ void* ImGui::MemAlloc(size_t size)
void ImGui::MemFree(void* ptr)
{
- if (ptr)
+ if (ptr)
if (ImGuiContext* ctx = GImGui)
ctx->IO.MetricsActiveAllocations--;
return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
@@ -2896,7 +3071,7 @@ bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si
return !error;
}
-void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data)
+void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
{
GImAllocatorAllocFunc = alloc_func;
GImAllocatorFreeFunc = free_func;
@@ -2994,18 +3169,27 @@ ImDrawListSharedData* ImGui::GetDrawListSharedData()
void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
{
// Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
+ // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
+ // This is because we want ActiveId to be set even when the window is not permitted to move.
ImGuiContext& g = *GImGui;
FocusWindow(window);
SetActiveID(window->MoveId, window);
g.NavDisableHighlight = true;
g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
- if (!(window->Flags & ImGuiWindowFlags_NoMove) && !(window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
+
+ bool can_move_window = true;
+ if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
+ can_move_window = false;
+ if (ImGuiDockNode* node = window->DockNodeAsHost)
+ if (node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove))
+ can_move_window = false;
+ if (can_move_window)
g.MovingWindow = window;
}
// Handle mouse moving window
// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
-void ImGui::UpdateMouseMovingWindow()
+void ImGui::UpdateMouseMovingWindowNewFrame()
{
ImGuiContext& g = *GImGui;
if (g.MovingWindow != NULL)
@@ -3057,6 +3241,57 @@ void ImGui::UpdateMouseMovingWindow()
}
}
+// Initiate moving window, handle left-click and right-click focus
+void ImGui::UpdateMouseMovingWindowEndFrame()
+{
+ // Initiate moving window
+ ImGuiContext& g = *GImGui;
+ if (g.ActiveId != 0 || g.HoveredId != 0)
+ return;
+
+ // Unless we just made a window/popup appear
+ if (g.NavWindow && g.NavWindow->Appearing)
+ return;
+
+ // Click to focus window and start moving (after we're done with all our widgets)
+ if (g.IO.MouseClicked[0])
+ {
+ if (g.HoveredRootWindow != NULL)
+ {
+ StartMouseMovingWindow(g.HoveredWindow);
+ if (g.IO.ConfigWindowsMoveFromTitleBarOnly && (!(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar) || g.HoveredWindow->RootWindowDockStop->DockIsActive))
+ if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
+ g.MovingWindow = NULL;
+ }
+ else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
+ {
+ // Clicking on void disable focus
+ FocusWindow(NULL);
+ }
+ }
+
+ // With right mouse button we close popups without changing focus
+ // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger)
+ if (g.IO.MouseClicked[1])
+ {
+ // Find the top-most window between HoveredWindow and the front most Modal Window.
+ // This is where we can trim the popup stack.
+ ImGuiWindow* modal = GetFrontMostPopupModal();
+ bool hovered_window_above_modal = false;
+ if (modal == NULL)
+ hovered_window_above_modal = true;
+ for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
+ {
+ ImGuiWindow* window = g.Windows[i];
+ if (window == modal)
+ break;
+ if (window == g.HoveredWindow)
+ hovered_window_above_modal = true;
+ }
+ ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal);
+ }
+}
+
static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
{
window->Pos += delta;
@@ -3248,8 +3483,8 @@ void ImGui::NewFrame()
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
ImGuiContext& g = *GImGui;
-#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS
- ImGuiTestEngineHook_PreNewFrame();
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ ImGuiTestEngineHook_PreNewFrame(&g);
#endif
// Check user data
@@ -3269,9 +3504,9 @@ void ImGui::NewFrame()
if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
- // Perform simple check: the beta io.ConfigResizeWindowsFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
- if (g.IO.ConfigResizeWindowsFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
- g.IO.ConfigResizeWindowsFromEdges = false;
+ // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
+ if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
+ g.IO.ConfigWindowsResizeFromEdges = false;
// Perform simple checks: multi-viewport and platform windows support
if (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@@ -3285,6 +3520,7 @@ void ImGui::NewFrame()
IM_ASSERT(g.PlatformIO.Platform_SetWindowPos != NULL && "Platform init didn't install handlers?");
IM_ASSERT(g.PlatformIO.Platform_GetWindowSize != NULL && "Platform init didn't install handlers?");
IM_ASSERT(g.PlatformIO.Platform_SetWindowSize != NULL && "Platform init didn't install handlers?");
+ IM_ASSERT(g.PlatformIO.Monitors.Size > 0 && "Platform init didn't setup Monitors list?");
IM_ASSERT((g.Viewports[0]->PlatformUserData != NULL || g.Viewports[0]->PlatformHandle != NULL) && "Platform init didn't setup main viewport.");
if (g.IO.ConfigDockingTransparentPayload && (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable))
IM_ASSERT(g.PlatformIO.Platform_SetWindowAlpha != NULL && "Platform_SetWindowAlpha handler is required to use io.ConfigDockingTransparent!");
@@ -3338,7 +3574,7 @@ void ImGui::NewFrame()
g.WindowsActiveCount = 0;
g.ConfigFlagsForFrame = g.IO.ConfigFlags;
- UpdateViewports();
+ UpdateViewportsNewFrame();
// Setup current font, and draw list shared data
// FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal!
@@ -3413,15 +3649,15 @@ void ImGui::NewFrame()
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
// Undocking
- // (needs to be before UpdateMouseMovingWindow so the window is already offset and following the mouse on the detaching frame)
+ // (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame)
DockContextNewFrameUpdateUndocking(&g);
// Find hovered window
- // (needs to be before UpdateMouseMovingWindow() so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
+ // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
UpdateHoveredWindowAndCaptureFlags();
// Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
- UpdateMouseMovingWindow();
+ UpdateMouseMovingWindowNewFrame();
// Background darkening/whitening
if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
@@ -3465,7 +3701,7 @@ void ImGui::NewFrame()
// No window should be open at the beginning of the frame.
// But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
g.CurrentWindowStack.resize(0);
- g.CurrentPopupStack.resize(0);
+ g.BeginPopupStack.resize(0);
ClosePopupsOverWindow(g.NavWindow);
// Docking
@@ -3476,9 +3712,10 @@ void ImGui::NewFrame()
// This fallback is particularly important as it avoid ImGui:: calls from crashing.
SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver);
Begin("Debug##Default");
+ g.FrameScopePushedImplicitWindow = true;
-#ifdef IMGUI_ENABLE_TEST_ENGINE_HOOKS
- ImGuiTestEngineHook_PostNewFrame();
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ ImGuiTestEngineHook_PostNewFrame(&g);
#endif
}
@@ -3490,7 +3727,7 @@ void ImGui::Initialize(ImGuiContext* context)
// Add .ini handle for ImGuiWindow type
ImGuiSettingsHandler ini_handler;
ini_handler.TypeName = "Window";
- ini_handler.TypeHash = ImHash("Window", 0, 0);
+ ini_handler.TypeHash = ImHashStr("Window", 0);
ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen;
ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine;
ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll;
@@ -3563,7 +3800,7 @@ void ImGui::Shutdown(ImGuiContext* context)
g.StyleModifiers.clear();
g.FontStack.clear();
g.OpenPopupStack.clear();
- g.CurrentPopupStack.clear();
+ g.BeginPopupStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
for (int i = 0; i < g.Viewports.Size; i++)
IM_DELETE(g.Viewports[i]);
@@ -3720,41 +3957,19 @@ void ImGui::PopClipRect()
window->ClipRect = window->DrawList->_ClipRectStack.back();
}
-static ImGuiWindow* FindFromMostVisibleChildWindow(ImGuiWindow* window)
+static ImGuiWindow* FindFrontMostVisibleChildWindow(ImGuiWindow* window)
{
for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--)
if (IsWindowActiveAndVisible(window->DC.ChildWindows[n]))
- return FindFromMostVisibleChildWindow(window->DC.ChildWindows[n]);
+ return FindFrontMostVisibleChildWindow(window->DC.ChildWindows[n]);
return window;
}
-// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
-void ImGui::EndFrame()
+static void ImGui::EndFrameDrawDimmedBackgrounds()
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(g.Initialized);
- if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times.
- return;
- IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()");
- // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
- if (g.PlatformIO.Platform_SetImeInputPos && ImLengthSqr(g.PlatformImePos - g.PlatformImeLastPos) > 0.0001f && g.PlatformImePosViewport && g.PlatformImePosViewport->PlatformWindowCreated)
- {
- g.PlatformIO.Platform_SetImeInputPos(g.PlatformImePosViewport, g.PlatformImePos);
- g.PlatformImeLastPos = g.PlatformImePos;
- g.PlatformImePosViewport = NULL;
- }
-
- // Hide implicit "Debug" window if it hasn't been used
- IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls, did you forget to call end on g.CurrentWindow->Name?
- if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
- g.CurrentWindow->Active = false;
- End();
-
- // Docking
- DockContextEndFrame(&g);
-
- // Draw modal whitening background on _other_ viewports than the one the modal or target are on
+ // Draw modal whitening background on _other_ viewports than the one the modal is one
ImGuiWindow* modal_window = GetFrontMostPopupModal();
const bool dim_bg_for_modal = (modal_window != NULL);
const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL);
@@ -3773,12 +3988,12 @@ void ImGui::EndFrame()
draw_list->AddRectFilled(viewport->Pos, viewport->Pos + viewport->Size, dim_bg_col);
}
- // CTRL-TAB
+ // Draw modal whitening background between CTRL-TAB list
if (dim_bg_for_window_list)
{
// Choose a draw list that will be front-most across all our children
ImGuiWindow* window = g.NavWindowingTargetAnim;
- ImDrawList* draw_list = FindFromMostVisibleChildWindow(window->RootWindow)->DrawList;
+ ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindow)->DrawList;
draw_list->PushClipRectFullScreen();
// Docking: draw modal whitening background on other nodes of a same dock tree
@@ -3798,8 +4013,52 @@ void ImGui::EndFrame()
draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
draw_list->PopClipRect();
}
+}
+
+// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
+void ImGui::EndFrame()
+{
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(g.Initialized);
+ if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times.
+ return;
+ IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?");
+
+ // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
+ if (g.PlatformIO.Platform_SetImeInputPos && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImePos - g.PlatformImeLastPos) > 0.0001f))
+ if (g.PlatformImePosViewport && g.PlatformImePosViewport->PlatformWindowCreated)
+ {
+ g.PlatformIO.Platform_SetImeInputPos(g.PlatformImePosViewport, g.PlatformImePos);
+ g.PlatformImeLastPos = g.PlatformImePos;
+ g.PlatformImePosViewport = NULL;
+ }
+
+ // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
+ // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
+ if (g.CurrentWindowStack.Size != 1)
+ {
+ if (g.CurrentWindowStack.Size > 1)
+ {
+ IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
+ while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING
+ End();
+ }
+ else
+ {
+ IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
+ }
+ }
- // Show CTRL+TAB list
+ // Hide implicit/fallback "Debug" window if it hasn't been used
+ g.FrameScopePushedImplicitWindow = false;
+ if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
+ g.CurrentWindow->Active = false;
+ End();
+
+ // Draw modal whitening background on _other_ viewports than the one the modal is one
+ EndFrameDrawDimmedBackgrounds();
+
+ // Show CTRL+TAB list window
if (g.NavWindowingTarget)
NavUpdateWindowingList();
@@ -3822,58 +4081,15 @@ void ImGui::EndFrame()
g.DragDropWithinSourceOrTarget = false;
}
- // Initiate moving window
- if (g.ActiveId == 0 && g.HoveredId == 0)
- {
- if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear
- {
- // Click to focus window and start moving (after we're done with all our widgets)
- if (g.IO.MouseClicked[0])
- {
- if (g.HoveredRootWindow != NULL)
- StartMouseMovingWindow(g.HoveredWindow);
- else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
- FocusWindow(NULL); // Clicking on void disable focus
- }
+ // End frame
+ g.FrameScopeActive = false;
+ g.FrameCountEnded = g.FrameCount;
- // With right mouse button we close popups without changing focus
- // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger)
- if (g.IO.MouseClicked[1])
- {
- // Find the top-most window between HoveredWindow and the front most Modal Window.
- // This is where we can trim the popup stack.
- ImGuiWindow* modal = GetFrontMostPopupModal();
- bool hovered_window_above_modal = false;
- if (modal == NULL)
- hovered_window_above_modal = true;
- for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
- {
- ImGuiWindow* window = g.Windows[i];
- if (window == modal)
- break;
- if (window == g.HoveredWindow)
- hovered_window_above_modal = true;
- }
- ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal);
- }
- }
- }
+ // Initiate moving window + handle left-click and right-click focus
+ UpdateMouseMovingWindowEndFrame();
- // Update user-facing viewport list
- g.PlatformIO.MainViewport = g.Viewports[0];
- g.PlatformIO.Viewports.resize(0);
- for (int i = 0; i < g.Viewports.Size; i++)
- {
- ImGuiViewportP* viewport = g.Viewports[i];
- viewport->LastPos = viewport->Pos;
- if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f)
- continue;
- if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window))
- continue;
- if (i > 0)
- IM_ASSERT(viewport->Window != NULL);
- g.PlatformIO.Viewports.push_back(viewport);
- }
+ // Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some)
+ UpdateViewportsEndFrame();
// Sort the window list so that all child windows are after their parent
// We cannot do that on FocusWindow() because childs may not exist yet
@@ -3897,11 +4113,8 @@ void ImGui::EndFrame()
// Clear Input data for next frame
g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
- memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
+ g.IO.InputQueueCharacters.resize(0);
memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
-
- g.FrameScopeActive = false;
- g.FrameCountEnded = g.FrameCount;
}
void ImGui::Render()
@@ -3947,7 +4160,7 @@ void ImGui::Render()
g.IO.MetricsRenderIndices += viewport->DrawData->TotalIdxCount;
}
- // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
+ // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (g.Viewports[0]->DrawData->CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
g.IO.RenderDrawListsFn(g.Viewports[0]->DrawData);
@@ -4024,8 +4237,8 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items
}
// Find window given position, search front-to-back
-// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically
-// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
+// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically
+// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
// called, aka before the next Begin(). Moving window isn't affected.
static void FindHoveredWindow()
{
@@ -4042,7 +4255,7 @@ static void FindHoveredWindow()
hovered_window = g.MovingWindow;
ImVec2 padding_regular = g.Style.TouchExtraPadding;
- ImVec2 padding_for_resize_from_edges = g.IO.ConfigResizeWindowsFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
+ ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
for (int i = g.Windows.Size - 1; i >= 0; i--)
{
ImGuiWindow* window = g.Windows[i];
@@ -4082,7 +4295,7 @@ static void FindHoveredWindow()
g.HoveredWindow = hovered_window;
g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
- g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
+ g.HoveredWindowUnderMovingWindow = g.MovingWindow ? hovered_window_ignoring_moving_window : NULL;
if (g.MovingWindow)
g.MovingWindow->Viewport = moving_window_viewport;
@@ -4136,7 +4349,8 @@ int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_
int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
{
ImGuiContext& g = *GImGui;
- if (key_index < 0) return false;
+ if (key_index < 0)
+ return 0;
IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
const float t = g.IO.KeysDownDuration[key_index];
return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
@@ -4145,7 +4359,8 @@ int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_r
bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
{
ImGuiContext& g = *GImGui;
- if (user_key_index < 0) return false;
+ if (user_key_index < 0)
+ return false;
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
const float t = g.IO.KeysDownDuration[user_key_index];
if (t == 0.0f)
@@ -4231,20 +4446,24 @@ ImVec2 ImGui::GetMousePos()
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
{
ImGuiContext& g = *GImGui;
- if (g.CurrentPopupStack.Size > 0)
- return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos;
+ if (g.BeginPopupStack.Size > 0)
+ return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos;
return g.IO.MousePos;
}
-// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position
+// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
{
- if (mouse_pos == NULL)
- mouse_pos = &GImGui->IO.MousePos;
+ // The assert is only to silence a false-positive in XCode Static Analysis.
+ // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).
+ IM_ASSERT(GImGui != NULL);
const float MOUSE_INVALID = -256000.0f;
- return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID;
+ ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
+ return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
}
+// Return the delta from the initial clicking position.
+// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
{
@@ -4424,6 +4643,11 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size
child_window->ChildId = id;
child_window->AutoFitChildAxises = auto_fit_axises;
+ // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
+ // While this is not really documented/defined, it seems that the expected thing to do.
+ if (child_window->BeginCount == 1)
+ parent_window->DC.CursorPos = child_window->Pos;
+
// Process navigation-in immediately so NavInit can run on first frame
if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
{
@@ -4511,14 +4735,14 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
{
// NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
ImGuiContext& g = *GImGui;
- int* p_backup = &window->DC.StackSizesBackup[0];
- { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
- { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
- { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
+ short* p_backup = &window->DC.StackSizesBackup[0];
+ { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
+ { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
+ { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
// For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
- { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
- { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
- { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont()
+ { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
+ { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
+ { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont()
IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
}
@@ -4538,7 +4762,7 @@ ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
ImGuiWindow* ImGui::FindWindowByName(const char* name)
{
- ImGuiID id = ImHash(name, 0);
+ ImGuiID id = ImHashStr(name, 0);
return FindWindowByID(id);
}
@@ -4560,7 +4784,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
{
// Retrieve settings from .ini file
- window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings);
+ window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
if (settings->ViewportId)
{
@@ -4646,6 +4870,8 @@ static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
static ImVec2 CalcSizeContents(ImGuiWindow* window)
{
+ if (window->Collapsed)
+ return window->SizeContents;
if (window->Hidden && window->HiddenFramesForResize == 0 && window->HiddenFramesRegular > 0)
return window->SizeContents;
@@ -4762,12 +4988,12 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co
struct ImGuiResizeGripDef
{
- ImVec2 CornerPos;
+ ImVec2 CornerPosN;
ImVec2 InnerDir;
int AngleMin12, AngleMax12;
};
-const ImGuiResizeGripDef resize_grip_def[4] =
+static const ImGuiResizeGripDef resize_grip_def[4] =
{
{ ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
{ ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
@@ -4779,10 +5005,10 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_
{
ImRect rect = window->Rect();
if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
- if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness);
- if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding);
- if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness);
- if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
+ if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top
+ if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right
+ if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom
+ if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left
IM_ASSERT(0);
return ImRect();
}
@@ -4797,10 +5023,10 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
return;
- const int resize_border_count = g.IO.ConfigResizeWindowsFromEdges ? 4 : 0;
+ const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
- const float grip_hover_outer_size = g.IO.ConfigResizeWindowsFromEdges ? RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS : 0.0f;
+ const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
ImVec2 pos_target(FLT_MAX, FLT_MAX);
ImVec2 size_target(FLT_MAX, FLT_MAX);
@@ -4810,7 +5036,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
{
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
- const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
+ const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
@@ -4832,8 +5058,8 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
{
// Resize from any of the four corners
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
- ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPos); // Corner of the window corresponding to our corner grip
- CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target);
+ ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip
+ CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
}
if (resize_grip_n == 0 || held || hovered)
resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
@@ -4841,22 +5067,23 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
for (int border_n = 0; border_n < resize_border_count; border_n++)
{
bool hovered, held;
- ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS);
+ ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
//GetOverlayDrawList(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
- if ((hovered && g.HoveredIdTimer > RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER) || held)
+ if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
{
g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
- if (held) *border_held = border_n;
+ if (held)
+ *border_held = border_n;
}
if (held)
{
ImVec2 border_target = window->Pos;
ImVec2 border_posn;
- if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
- if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
- if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
- if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS); }
+ if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top
+ if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right
+ if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom
+ if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left
CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
}
}
@@ -4899,7 +5126,46 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding)
{
- window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + window->Size, rect.Min + padding) - window->Size);
+ ImGuiContext& g = *GImGui;
+ ImVec2 size_for_clamping = (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size;
+ window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping);
+}
+
+static void ImGui::RenderOuterBorders(ImGuiWindow* window)
+{
+ ImGuiContext& g = *GImGui;
+ float rounding = window->WindowRounding;
+ float border_size = window->WindowBorderSize;
+ if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
+ window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
+
+ int border_held = window->ResizeBorderHeld;
+ if (border_held != -1)
+ {
+ struct ImGuiResizeBorderDef
+ {
+ ImVec2 InnerDir;
+ ImVec2 CornerPosN1, CornerPosN2;
+ float OuterAngle;
+ };
+ static const ImGuiResizeBorderDef resize_border_def[4] =
+ {
+ { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top
+ { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right
+ { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom
+ { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left
+ };
+ const ImGuiResizeBorderDef& def = resize_border_def[border_held];
+ ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
+ window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle);
+ window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f);
+ window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual
+ }
+ if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
+ {
+ float y = window->Pos.y + window->TitleBarHeight() - 1;
+ window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize);
+ }
}
void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
@@ -4907,14 +5173,18 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
window->ParentWindow = parent_window;
window->RootWindow = window->RootWindowDockStop = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
+ {
window->RootWindow = parent_window->RootWindow;
- if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
if (!window->DockIsActive && !(parent_window->Flags & ImGuiWindowFlags_DockNodeHost))
window->RootWindowDockStop = parent_window->RootWindowDockStop;
+ }
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
+ {
+ IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
+ }
}
// Push a new ImGui window to add widgets to.
@@ -4928,7 +5198,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
- IM_ASSERT(name != NULL); // Window name required
+ IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required
IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame()
IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
@@ -4957,7 +5227,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0);
if (flags & ImGuiWindowFlags_Popup)
{
- ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
+ ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
window_just_activated_by_user |= (window != popup_ref.Window);
}
@@ -4972,7 +5242,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->Flags = (ImGuiWindowFlags)flags;
window->LastFrameActive = current_frame;
window->BeginOrderWithinParent = 0;
- window->BeginOrderWithinContext = g.WindowsActiveCount++;
+ window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
}
else
{
@@ -5007,9 +5277,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
CheckStacksSize(window, true);
if (flags & ImGuiWindowFlags_Popup)
{
- ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
+ ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
popup_ref.Window = window;
- g.CurrentPopupStack.push_back(popup_ref);
+ g.BeginPopupStack.push_back(popup_ref);
window->PopupId = popup_ref.PopupId;
}
@@ -5052,7 +5322,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
}
- window->DockFamily = g.NextWindowData.DockFamily;
+ window->WindowClass = g.NextWindowData.WindowClass;
if (g.NextWindowData.CollapsedCond)
SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
if (g.NextWindowData.FocusCond)
@@ -5072,13 +5342,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
window->IDStack.resize(1);
- // Update stored window name when it changes (which can only happen with the "###" operator).
- // The title bar always display the 'name' parameter, so we only update storage if the title is displayed to the end-user in a different place.
- bool window_title_visible_elsewhere = (window->Viewport && window->Viewport->Window == window) || (window->DockIsActive);
- if (!window_just_created && window_title_visible_elsewhere && strcmp(name, window->Name) != 0)
+ // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
+ // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
+ bool window_title_visible_elsewhere = false;
+ if ((window->Viewport && window->Viewport->Window == window) || (window->DockIsActive))
+ window_title_visible_elsewhere = true;
+ else if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB
+ window_title_visible_elsewhere = true;
+ if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
{
- IM_DELETE(window->Name);
- window->Name = ImStrdup(name);
+ size_t buf_len = (size_t)window->NameBufLen;
+ window->Name = ImStrdupcpy(window->Name, &buf_len, name);
+ window->NameBufLen = (int)buf_len;
}
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
@@ -5119,9 +5394,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
flags = window->Flags;
// Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies)
- if (window->DockIsActive)
- window->WindowBorderSize = 0.0f;
- else if (flags & ImGuiWindowFlags_ChildWindow)
+ if (flags & ImGuiWindowFlags_ChildWindow)
window->WindowBorderSize = style.ChildBorderSize;
else
window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
@@ -5207,13 +5480,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
window->AutoPosLastDirection = ImGuiDir_None;
if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
- window->Pos = g.CurrentPopupStack.back().OpenPopupPos;
+ window->Pos = g.BeginPopupStack.back().OpenPopupPos;
}
// Position child window
if (flags & ImGuiWindowFlags_ChildWindow)
{
- window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size;
+ IM_ASSERT(parent_window && parent_window->Active);
+ window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
parent_window->DC.ChildWindows.push_back(window);
if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
window->Pos = parent_window->DC.CursorPos;
@@ -5229,10 +5503,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
window->Pos = FindBestWindowPosForPopup(window);
- if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned)
+ // Late create viewport if we don't fit within our current host viewport.
+ if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned && !window->Viewport->PlatformWindowMinimized)
if (!window->Viewport->GetRect().Contains(window->Rect()))
{
- // Late create viewport, based on the assumption that with our calculations, the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport)
+ // This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport)
//ImGuiViewport* old_viewport = window->Viewport;
window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoFocusOnAppearing);
@@ -5243,16 +5518,37 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetCurrentWindow(window);
}
- // Synchronize viewport --> window in case the platform window has been moved or resized from the OS/WM
if (window->ViewportOwned)
{
+ // Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM
if (window->Viewport->PlatformRequestMove)
window->Pos = window->Viewport->Pos;
if (window->Viewport->PlatformRequestResize)
window->Size = window->SizeFull = window->Viewport->Size;
+ // Update common viewport flags
+ ImGuiViewportFlags viewport_flags = (window->Viewport->Flags) & ~(ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration);
+ if (flags & ImGuiWindowFlags_Tooltip)
+ viewport_flags |= ImGuiViewportFlags_TopMost;
+ if (g.IO.ConfigViewportsNoTaskBarIcon || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0)
+ viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon;
+ if (g.IO.ConfigViewportsNoDecoration || (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0)
+ viewport_flags |= ImGuiViewportFlags_NoDecoration;
+ if ((viewport_flags & ImGuiViewportFlags_NoDecoration) && (viewport_flags & ImGuiViewportFlags_NoTaskBarIcon))
+ viewport_flags |= ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoFocusOnClick;
+
+ // We can overwrite viewport flags using ImGuiWindowClass (advanced users)
+ // We don't default to the main viewport because.
+ if (window->WindowClass.ParentViewportId)
+ window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId;
+ else
+ window->Viewport->ParentViewportId = g.IO.ConfigViewportsNoParent ? 0 : IMGUI_VIEWPORT_DEFAULT_ID;
+ if (window->WindowClass.ViewportFlagsOverrideMask)
+ viewport_flags = (viewport_flags & ~window->WindowClass.ViewportFlagsOverrideMask) | (window->WindowClass.ViewportFlagsOverrideValue & window->WindowClass.ViewportFlagsOverrideMask);
+
// We also tell the back-end that clearing the platform window won't be necessary, as our window is filling the viewport and we have disabled BgAlpha
- window->Viewport->Flags |= ImGuiViewportFlags_NoRendererClear;
+ viewport_flags |= ImGuiViewportFlags_NoRendererClear;
+ window->Viewport->Flags = viewport_flags;
}
// Clamp position so window stays visible within its viewport or monitor
@@ -5304,13 +5600,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
want_focus = true;
}
+ // Decide if we are going to handle borders and resize grips
+ const bool handle_borders_and_resize_grips = (window->DockNodeAsHost || !window->DockIsActive);
+
// Handle manual resize: Resize Grips, Borders, Gamepad
int border_held = -1;
ImU32 resize_grip_col[4] = { 0 };
- const int resize_grip_count = g.IO.ConfigResizeWindowsFromEdges ? 2 : 1; // 4
+ const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4
const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
- if (!window->Collapsed)
+ if (handle_borders_and_resize_grips && !window->Collapsed)
UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
+ window->ResizeBorderHeld = (signed char)border_held;
// Synchronize window --> viewport
if (window->ViewportOwned)
@@ -5361,6 +5661,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Draw window + handle manual resize
+ // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
const float window_rounding = window->WindowRounding;
const float window_border_size = window->WindowBorderSize;
const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
@@ -5413,7 +5714,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// in order for their pos/size to be matching their undocking state.)
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
{
- ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
+ ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
}
@@ -5422,7 +5723,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
ImRect menu_bar_rect = window->MenuBarRect();
menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
- window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
+ window->DrawList->AddRectFilled(menu_bar_rect.Min+ImVec2(window_border_size,0), menu_bar_rect.Max-ImVec2(window_border_size,0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
}
@@ -5449,12 +5750,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
Scrollbar(ImGuiLayoutType_Vertical);
// Render resize grips (after their input handling so we don't have a frame of latency)
- if (!(flags & ImGuiWindowFlags_NoResize))
+ if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize))
{
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
{
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
- const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
+ const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
@@ -5462,16 +5763,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
}
- // Borders
- if (window_border_size > 0.0f && !(flags & ImGuiWindowFlags_NoBackground))
- window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size);
- if (border_held != -1)
- {
- ImRect border = GetResizeBorderRect(window, border_held, grip_draw_size, 0.0f);
- window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size));
- }
- if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
- window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize, -1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
+ // Borders (for dock node host they will be rendered over after the tab bar)
+ if (handle_borders_and_resize_grips && !window->DockNodeAsHost)
+ RenderOuterBorders(window);
}
// Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
@@ -5496,7 +5790,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavHideHighlightOneFrame = false;
- window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f);
+ window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f);
window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
window->DC.NavLayerActiveMaskNext = 0x00;
window->DC.MenuBarAppending = false;
@@ -5542,6 +5836,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
window->Viewport->PlatformRequestClose = false;
g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue.
+ //IMGUI_DEBUG_LOG("Window '%s' PlatformRequestClose\n", window->Name);
*p_open = false;
}
}
@@ -5552,8 +5847,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Close & collapse button are on layer 1 (same as menus) and don't default focus
const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
- window->DC.NavLayerCurrent++;
- window->DC.NavLayerCurrentMask <<= 1;
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
// Collapse button
if (!(flags & ImGuiWindowFlags_NoCollapse))
@@ -5568,8 +5863,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
*p_open = false;
}
- window->DC.NavLayerCurrent--;
- window->DC.NavLayerCurrentMask >>= 1;
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
window->DC.ItemFlags = item_flags_backup;
// Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
@@ -5725,6 +6020,14 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use,
void ImGui::End()
{
ImGuiContext& g = *GImGui;
+
+ if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow)
+ {
+ IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!");
+ return; // FIXME-ERRORHANDLING
+ }
+ IM_ASSERT(g.CurrentWindowStack.Size > 0);
+
ImGuiWindow* window = g.CurrentWindow;
if (window->DC.ColumnsSet != NULL)
@@ -5744,7 +6047,7 @@ void ImGui::End()
// Pop from window stack
g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup)
- g.CurrentPopupStack.pop_back();
+ g.BeginPopupStack.pop_back();
CheckStacksSize(window, false);
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
if (g.CurrentWindow)
@@ -5807,7 +6110,7 @@ void ImGui::FocusWindow(ImGuiWindow* window)
g.NavInitRequest = false;
g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
g.NavIdIsAlive = false;
- g.NavLayer = 0;
+ g.NavLayer = ImGuiNavLayer_Main;
//IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
}
@@ -6231,7 +6534,7 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
}
}
-ImGuiID ImGui::GetWindowDockId()
+ImGuiID ImGui::GetWindowDockID()
{
ImGuiContext& g = *GImGui;
return g.CurrentWindow->DockId;
@@ -6492,17 +6795,17 @@ void ImGui::SetNextWindowViewport(ImGuiID id)
g.NextWindowData.ViewportId = id;
}
-void ImGui::SetNextWindowDockId(ImGuiID id, ImGuiCond cond)
+void ImGui::SetNextWindowDockID(ImGuiID id, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
g.NextWindowData.DockCond = cond ? cond : ImGuiCond_Always;
g.NextWindowData.DockId = id;
}
-void ImGui::SetNextWindowDockFamily(const ImGuiDockFamily* family)
+void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class)
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.DockFamily = *family;
+ g.NextWindowData.WindowClass = *window_class;
}
// In window space (not screen space!)
@@ -6665,10 +6968,10 @@ ImVec2 ImGui::GetCursorScreenPos()
return window->DC.CursorPos;
}
-void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
+void ImGui::SetCursorScreenPos(const ImVec2& pos)
{
ImGuiWindow* window = GetCurrentWindow();
- window->DC.CursorPos = screen_pos;
+ window->DC.CursorPos = pos;
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
}
@@ -6706,12 +7009,12 @@ void ImGui::SetScrollY(float scroll_y)
window->ScrollTargetCenterRatio.y = 0.0f;
}
-void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio)
+void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
{
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
- window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y);
+ window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y);
window->ScrollTargetCenterRatio.y = center_y_ratio;
}
@@ -6757,71 +7060,74 @@ void ImGui::SetItemDefaultFocus()
void ImGui::SetStateStorage(ImGuiStorage* tree)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiWindow* window = GImGui->CurrentWindow;
window->DC.StateStorage = tree ? tree : &window->StateStorage;
}
ImGuiStorage* ImGui::GetStateStorage()
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
return window->DC.StateStorage;
}
void ImGui::PushID(const char* str_id)
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
window->IDStack.push_back(window->GetIDNoKeepAlive(str_id));
}
void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end));
}
void ImGui::PushID(const void* ptr_id)
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
}
void ImGui::PushID(int int_id)
{
const void* ptr_id = (void*)(intptr_t)int_id;
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
}
void ImGui::PopID()
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
window->IDStack.pop_back();
}
ImGuiID ImGui::GetID(const char* str_id)
{
- return GImGui->CurrentWindow->GetID(str_id);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->GetID(str_id);
}
ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
{
- return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->GetID(str_id_begin, str_id_end);
}
ImGuiID ImGui::GetID(const void* ptr_id)
{
- return GImGui->CurrentWindow->GetID(ptr_id);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->GetID(ptr_id);
}
bool ImGui::IsRectVisible(const ImVec2& size)
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;;
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
}
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;;
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
}
@@ -7011,13 +7317,13 @@ void ImGui::SetTooltip(const char* fmt, ...)
bool ImGui::IsPopupOpen(ImGuiID id)
{
ImGuiContext& g = *GImGui;
- return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
+ return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
}
bool ImGui::IsPopupOpen(const char* str_id)
{
ImGuiContext& g = *GImGui;
- return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
+ return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
}
ImGuiWindow* ImGui::GetFrontMostPopupModal()
@@ -7044,7 +7350,7 @@ void ImGui::OpenPopupEx(ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* parent_window = g.CurrentWindow;
- int current_stack_size = g.CurrentPopupStack.Size;
+ int current_stack_size = g.BeginPopupStack.Size;
ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
popup_ref.PopupId = id;
popup_ref.Window = NULL;
@@ -7054,7 +7360,7 @@ void ImGui::OpenPopupEx(ImGuiID id)
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
- //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id);
+ //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id);
if (g.OpenPopupStack.Size < current_stack_size + 1)
{
g.OpenPopupStack.push_back(popup_ref);
@@ -7103,12 +7409,13 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
// Don't close our own child popup windows.
- int n = 0;
+ int popup_count_to_keep = 0;
if (ref_window)
{
- for (n = 0; n < g.OpenPopupStack.Size; n++)
+ // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
+ for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
{
- ImGuiPopupRef& popup = g.OpenPopupStack[n];
+ ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep];
if (!popup.Window)
continue;
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
@@ -7116,47 +7423,73 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
continue;
// Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
- bool has_focus = false;
- for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
- has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow);
- if (!has_focus)
+ bool popup_or_descendent_has_focus = false;
+ for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++)
+ if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow)
+ popup_or_descendent_has_focus = true;
+ if (!popup_or_descendent_has_focus)
break;
}
}
- if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below
- ClosePopupToLevel(n);
+ if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
+ {
+ //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
+ ClosePopupToLevel(popup_count_to_keep, false);
+ }
}
-void ImGui::ClosePopupToLevel(int remaining)
+void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under)
{
IM_ASSERT(remaining >= 0);
ImGuiContext& g = *GImGui;
ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow;
- if (g.NavLayer == 0)
- focus_window = NavRestoreLastChildNavWindow(focus_window);
- FocusWindow(focus_window);
- focus_window->DC.NavHideHighlightOneFrame = true;
g.OpenPopupStack.resize(remaining);
-}
-void ImGui::ClosePopup(ImGuiID id)
-{
- if (!IsPopupOpen(id))
- return;
- ImGuiContext& g = *GImGui;
- ClosePopupToLevel(g.OpenPopupStack.Size - 1);
+ // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely.
+ // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing.
+ // The current code will set focus to the parent of the popup window which is incorrect.
+ // It rarely manifested until now because UpdateMouseMovingWindowNewFrame() would call FocusWindow() again on the clicked window,
+ // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again.
+ // However if the clicked window has the _NoMove flag set we would be left with B focused.
+ // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway,
+ // but we should inspect and fix this properly.
+ if (apply_focus_to_window_under)
+ {
+ if (g.NavLayer == 0)
+ focus_window = NavRestoreLastChildNavWindow(focus_window);
+ FocusWindow(focus_window);
+ }
}
// Close the popup we have begin-ed into.
void ImGui::CloseCurrentPopup()
{
ImGuiContext& g = *GImGui;
- int popup_idx = g.CurrentPopupStack.Size - 1;
- if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
+ int popup_idx = g.BeginPopupStack.Size - 1;
+ if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
return;
- while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
+
+ // Closing a menu closes its top-most parent popup (unless a modal)
+ while (popup_idx > 0)
+ {
+ ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
+ ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
+ bool close_parent = false;
+ if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
+ if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
+ close_parent = true;
+ if (!close_parent)
+ break;
popup_idx--;
- ClosePopupToLevel(popup_idx);
+ }
+ //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
+ ClosePopupToLevel(popup_idx, true);
+
+ // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
+ // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
+ // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
+ if (ImGuiWindow* window = g.NavWindow)
+ window->DC.NavHideHighlightOneFrame = true;
}
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
@@ -7170,7 +7503,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
char name[20];
if (extra_flags & ImGuiWindowFlags_ChildMenu)
- ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
+ ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
else
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
@@ -7184,7 +7517,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
- if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
+ if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
{
g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
return false;
@@ -7193,6 +7526,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
}
+// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
+// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
@@ -7215,7 +7550,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
{
EndPopup();
if (is_open)
- ClosePopup(id);
+ ClosePopupToLevel(g.BeginPopupStack.Size, true);
return false;
}
return is_open;
@@ -7223,9 +7558,9 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
void ImGui::EndPopup()
{
- ImGuiContext& g = *GImGui; (void)g;
+ ImGuiContext& g = *GImGui;
IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
- IM_ASSERT(g.CurrentPopupStack.Size > 0);
+ IM_ASSERT(g.BeginPopupStack.Size > 0);
// Make all menus and popups wrap around for now, may need to expose that policy.
NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY);
@@ -7399,7 +7734,7 @@ ImGuiViewport* ImGui::GetMainViewport()
return g.Viewports[0];
}
-ImGuiViewportP* ImGui::FindViewportByID(ImGuiID id)
+ImGuiViewport* ImGui::FindViewportByID(ImGuiID id)
{
ImGuiContext& g = *GImGui;
for (int n = 0; n < g.Viewports.Size; n++)
@@ -7427,6 +7762,7 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view
if (g.CurrentViewport == viewport)
return;
g.CurrentViewport = viewport;
+ //IMGUI_DEBUG_LOG("SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0);
// Notify platform layer of viewport changes
// FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI
@@ -7445,9 +7781,9 @@ static bool ImGui::GetWindowAlwaysWantOwnViewport(ImGuiWindow* window)
{
// Tooltips and menus are not automatically forced into their own viewport when the NoMerge flag is set, however the multiplication of viewports makes them more likely to protude and create their own.
ImGuiContext& g = *GImGui;
- if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoMerge) && (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable))
+ if (g.IO.ConfigViewportsNoAutoMerge && (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable))
if (!window->DockIsActive)
- if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip)) == 0)
+ if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) == 0)
return true;
return false;
}
@@ -7517,20 +7853,30 @@ static ImGuiViewportP* FindViewportHoveredFromPlatformWindowStack(const ImVec2 m
return best_candidate;
}
-// Called in NewFrame()
-static void ImGui::UpdateViewports()
+static void ImGui::UpdateViewportsNewFrame()
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.PlatformIO.Viewports.Size <= g.Viewports.Size);
- // Update main viewport with current platform position and size
+ // Update Minimized status (we need it first in order to decide if we'll apply Pos/Size of the main viewport)
+ for (int n = 0; n < g.Viewports.Size; n++)
+ {
+ ImGuiViewportP* viewport = g.Viewports[n];
+ const bool platform_funcs_available = (n == 0 || viewport->PlatformWindowCreated);
+ if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable))
+ if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available)
+ viewport->PlatformWindowMinimized = g.PlatformIO.Platform_GetWindowMinimized(viewport);
+ }
+
+ // Create/update main viewport with current platform position and size
ImGuiViewportP* main_viewport = g.Viewports[0];
IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID);
IM_ASSERT(main_viewport->Window == NULL);
ImVec2 main_viewport_platform_pos = ImVec2(0.0f, 0.0f);
- if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable))
- main_viewport_platform_pos = g.PlatformIO.Platform_GetWindowPos(main_viewport);
- AddUpdateViewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, main_viewport_platform_pos, g.IO.DisplaySize, ImGuiViewportFlags_CanHostOtherWindows);
+ ImVec2 main_viewport_platform_size = g.IO.DisplaySize;
+ if (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)
+ main_viewport_platform_pos = main_viewport->PlatformWindowMinimized ? main_viewport->Pos : g.PlatformIO.Platform_GetWindowPos(main_viewport);
+ AddUpdateViewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, main_viewport_platform_pos, main_viewport_platform_size, ImGuiViewportFlags_CanHostOtherWindows);
g.CurrentViewport = NULL;
g.MouseViewport = NULL;
@@ -7565,9 +7911,6 @@ static void ImGui::UpdateViewports()
const bool platform_funcs_available = (n == 0 || viewport->PlatformWindowCreated);
if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable))
{
- if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available)
- viewport->PlatformWindowMinimized = g.PlatformIO.Platform_GetWindowMinimized(viewport);
-
// Update Position and Size (from Platform Window to ImGui) if requested.
// We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities.
if (!viewport->PlatformWindowMinimized && platform_funcs_available)
@@ -7595,8 +7938,10 @@ static void ImGui::UpdateViewports()
// Update DPI scale
float new_dpi_scale;
- if (g.PlatformIO.Platform_GetWindowDpiScale)
+ if (g.PlatformIO.Platform_GetWindowDpiScale && platform_funcs_available)
new_dpi_scale = g.PlatformIO.Platform_GetWindowDpiScale(viewport);
+ else if (viewport->PlatformMonitor != -1)
+ new_dpi_scale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale;
else
new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f;
if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale)
@@ -7627,7 +7972,7 @@ static void ImGui::UpdateViewports()
ImGuiViewportP* viewport_hovered = NULL;
if (g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
{
- viewport_hovered = g.IO.MouseHoveredViewport ? FindViewportByID(g.IO.MouseHoveredViewport) : NULL;
+ viewport_hovered = g.IO.MouseHoveredViewport ? (ImGuiViewportP*)FindViewportByID(g.IO.MouseHoveredViewport) : NULL;
if (viewport_hovered && (viewport_hovered->Flags & ImGuiViewportFlags_NoInputs))
{
// Back-end failed at honoring its contract if it returned a viewport with the _NoInputs flag.
@@ -7668,6 +8013,28 @@ static void ImGui::UpdateViewports()
IM_ASSERT(g.MouseViewport != NULL);
}
+// Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some)
+static void ImGui::UpdateViewportsEndFrame()
+{
+ ImGuiContext& g = *GImGui;
+ g.PlatformIO.MainViewport = g.Viewports[0];
+ g.PlatformIO.Viewports.resize(0);
+ for (int i = 0; i < g.Viewports.Size; i++)
+ {
+ ImGuiViewportP* viewport = g.Viewports[i];
+ viewport->LastPos = viewport->Pos;
+ if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f)
+ if (i > 0) // Always include main viewport in the list
+ continue;
+ if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window))
+ continue;
+ if (i > 0)
+ IM_ASSERT(viewport->Window != NULL);
+ g.PlatformIO.Viewports.push_back(viewport);
+ }
+ g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called
+}
+
// FIXME: We should ideally refactor the system to call this every frame (we currently don't)
ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& pos, const ImVec2& size, ImGuiViewportFlags flags)
{
@@ -7687,8 +8054,10 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id);
if (viewport)
{
- viewport->Pos = pos;
- viewport->Size = size;
+ if (!viewport->PlatformRequestMove)
+ viewport->Pos = pos;
+ if (!viewport->PlatformRequestResize)
+ viewport->Size = size;
}
else
{
@@ -7707,10 +8076,10 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport->Pos.x + viewport->Size.x);
g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport->Pos.y + viewport->Size.y);
- // Request an initial DpiScale before the OS platform window creation
+ // Store initial DpiScale before the OS platform window creation, based on expected monitor data.
// This is so we can select an appropriate font size on the first frame of our window lifetime
- if (g.PlatformIO.Platform_GetWindowDpiScale)
- viewport->DpiScale = g.PlatformIO.Platform_GetWindowDpiScale(viewport);
+ if (viewport->PlatformMonitor != -1)
+ viewport->DpiScale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale;
}
viewport->Window = window;
@@ -7757,7 +8126,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
// Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file
if (window->Viewport == NULL && window->ViewportId != 0)
{
- window->Viewport = FindViewportByID(window->ViewportId);
+ window->Viewport = (ImGuiViewportP*)FindViewportByID(window->ViewportId);
if (window->Viewport == NULL && window->ViewportPos.x != FLT_MAX && window->ViewportPos.y != FLT_MAX)
window->Viewport = AddUpdateViewport(window, window->ID, window->ViewportPos, window->Size, ImGuiViewportFlags_None);
}
@@ -7766,7 +8135,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
if (g.NextWindowData.ViewportCond)
{
// Code explicitly request a viewport
- window->Viewport = FindViewportByID(g.NextWindowData.ViewportId);
+ window->Viewport = (ImGuiViewportP*)FindViewportByID(g.NextWindowData.ViewportId);
window->ViewportId = g.NextWindowData.ViewportId; // Store ID even if Viewport isn't resolved yet.
}
else if ((flags & ImGuiWindowFlags_ChildWindow) || (flags & ImGuiWindowFlags_ChildMenu))
@@ -7805,7 +8174,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
{
// We need to take account of the possibility that mouse may become invalid.
// Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds.
- ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.CurrentPopupStack.back().OpenMousePos;
+ ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.BeginPopupStack.back().OpenMousePos;
bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow);
bool mouse_valid = IsMousePosValid(&mouse_ref);
if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid))
@@ -7847,7 +8216,8 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
window->ViewportId = window->Viewport->ID;
}
-// Called by imgui at the end of the main loop, after EndFrame()
+// Called by user at the end of the main loop, after EndFrame()
+// This will handle the creation/update of all OS windows via function defined in the ImGuiPlatformIO api.
void ImGui::UpdatePlatformWindows()
{
ImGuiContext& g = *GImGui;
@@ -7872,37 +8242,22 @@ void ImGui::UpdatePlatformWindows()
DestroyPlatformWindow(viewport);
continue;
}
- if (viewport->LastFrameActive < g.FrameCount)
- continue;
- // New windows that appears directly in a new viewport won't always have a size on their frame
- if (viewport->Size.x <= 0 || viewport->Size.y <= 0)
+ // New windows that appears directly in a new viewport won't always have a size on their first frame
+ if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0 || viewport->Size.y <= 0)
continue;
- // Update common viewport flags for owned viewports
- if (viewport->Window != NULL)
- {
- ImGuiViewportFlags flags = viewport->Flags & ~(ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration);
- if (viewport->Window->Flags & ImGuiWindowFlags_Tooltip)
- flags |= ImGuiViewportFlags_TopMost;
- if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) != 0 || (viewport->Window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0)
- flags |= ImGuiViewportFlags_NoTaskBarIcon;
- if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) == 0 || (viewport->Window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0)
- flags |= ImGuiViewportFlags_NoDecoration;
- viewport->Flags = flags;
- }
-
// Create window
- bool is_new_window = (viewport->PlatformWindowCreated == false);
- if (is_new_window)
+ bool is_new_platform_window = (viewport->PlatformWindowCreated == false);
+ if (is_new_platform_window)
{
//IMGUI_DEBUG_LOG("Create Platform Window %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
g.PlatformIO.Platform_CreateWindow(viewport);
if (g.PlatformIO.Renderer_CreateWindow != NULL)
g.PlatformIO.Renderer_CreateWindow(viewport);
viewport->LastNameHash = 0;
- viewport->LastPlatformPos = viewport->LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX); // By clearing those we'll enforce a call to Platform_SetWindowPos/Platform_SetWindowSize before Platform_ShowWindow
- viewport->LastRendererSize = viewport->Size;
+ viewport->LastPlatformPos = viewport->LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX); // By clearing those we'll enforce a call to Platform_SetWindowPos/Size below, before Platform_ShowWindow (FIXME: Is that necessary?)
+ viewport->LastRendererSize = viewport->Size; // We don't need to call Renderer_SetWindowSize() as it is expected Renderer_CreateWindow() already did it.
viewport->PlatformWindowCreated = true;
}
@@ -7921,36 +8276,43 @@ void ImGui::UpdatePlatformWindows()
{
const char* title_begin = window_for_title->Name;
char* title_end = (char*)(intptr_t)FindRenderedTextEnd(title_begin);
- const ImGuiID title_hash = ImHash(title_begin, (int)(title_end - title_begin));
+ const ImGuiID title_hash = ImHashStr(title_begin, title_end - title_begin);
if (viewport->LastNameHash != title_hash)
{
char title_end_backup_c = *title_end;
- *title_end = 0; // Cut existing buffer short instead of doing an alloc/free
+ *title_end = 0; // Cut existing buffer short instead of doing an alloc/free, no small gain.
g.PlatformIO.Platform_SetWindowTitle(viewport, title_begin);
*title_end = title_end_backup_c;
viewport->LastNameHash = title_hash;
}
}
- // Update alpha
+ // Update alpha (if it changed)
if (viewport->LastAlpha != viewport->Alpha && g.PlatformIO.Platform_SetWindowAlpha)
g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport->Alpha);
viewport->LastAlpha = viewport->Alpha;
- // Show window. On startup ensure platform window don't get focus
- if (is_new_window)
+ // Optional, general purpose call to allow the back-end to perform general book-keeping even if things haven't changed.
+ if (g.PlatformIO.Platform_UpdateWindow)
+ g.PlatformIO.Platform_UpdateWindow(viewport);
+
+ if (is_new_platform_window)
{
- if (g.FrameCount < 3) // Give a few frames for the application to stabilize (nested contents may lead to viewport being created a few frames late)
+ // On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late)
+ if (g.FrameCount < 3)
viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing;
+
+ // Show window
g.PlatformIO.Platform_ShowWindow(viewport);
- }
- // Even without focus, we assume the window becomes front-most. This is used by our platform z-order heuristic when io.MouseHoveredViewport is not available.
- if (is_new_window && viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount)
- viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount;
+ // Even without focus, we assume the window becomes front-most.
+ // This is useful for our platform z-order heuristic when io.MouseHoveredViewport is not available.
+ if (viewport->LastFrontMostStampCount != g.WindowsFrontMostStampCount)
+ viewport->LastFrontMostStampCount = ++g.WindowsFrontMostStampCount;
+ }
// Clear request flags
- viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false;
+ viewport->ClearRequestFlags();
}
// Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport.
@@ -7974,6 +8336,34 @@ void ImGui::UpdatePlatformWindows()
}
}
+// This is a default/basic function for performing the rendering/swap of multiple Platform Windows.
+// Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves.
+// The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself:
+//
+// ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+// for (int i = 1; i < platform_io.Viewports.Size; i++)
+// MyRenderFunction(platform_io.Viewports[i], my_args);
+// for (int i = 1; i < platform_io.Viewports.Size; i++)
+// MySwapBufferFunction(platform_io.Viewports[i], my_args);
+//
+void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* renderer_render_arg)
+{
+ // Skip the main viewport (index 0), which is always fully handled by the application!
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ for (int i = 1; i < platform_io.Viewports.Size; i++)
+ {
+ ImGuiViewport* viewport = platform_io.Viewports[i];
+ if (platform_io.Platform_RenderWindow) platform_io.Platform_RenderWindow(viewport, platform_render_arg);
+ if (platform_io.Renderer_RenderWindow) platform_io.Renderer_RenderWindow(viewport, renderer_render_arg);
+ }
+ for (int i = 1; i < platform_io.Viewports.Size; i++)
+ {
+ ImGuiViewport* viewport = platform_io.Viewports[i];
+ if (platform_io.Platform_SwapBuffers) platform_io.Platform_SwapBuffers(viewport, platform_render_arg);
+ if (platform_io.Renderer_SwapBuffers) platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg);
+ }
+}
+
static int ImGui::FindPlatformMonitorForPos(const ImVec2& pos)
{
ImGuiContext& g = *GImGui;
@@ -8015,37 +8405,6 @@ static int ImGui::FindPlatformMonitorForRect(const ImRect& rect)
return best_monitor_n;
}
-// This is a default/basic function for performing the rendering/swap of multiple platform windows.
-// Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves.
-// The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself:
-//
-// ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
-// for (int i = 1; i < platform_io.Viewports.Size; i++)
-// MyRenderFunction(platform_io.Viewports[i], my_args);
-// for (int i = 1; i < platform_io.Viewports.Size; i++)
-// MySwapBufferFunction(platform_io.Viewports[i], my_args);
-//
-void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* renderer_render_arg)
-{
- if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
- return;
-
- // Skip the main viewport (index 0), which is always fully handled by the application!
- ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
- for (int i = 1; i < platform_io.Viewports.Size; i++)
- {
- ImGuiViewport* viewport = platform_io.Viewports[i];
- if (platform_io.Platform_RenderWindow) platform_io.Platform_RenderWindow(viewport, platform_render_arg);
- if (platform_io.Renderer_RenderWindow) platform_io.Renderer_RenderWindow(viewport, renderer_render_arg);
- }
- for (int i = 1; i < platform_io.Viewports.Size; i++)
- {
- ImGuiViewport* viewport = platform_io.Viewports[i];
- if (platform_io.Platform_SwapBuffers) platform_io.Platform_SwapBuffers(viewport, platform_render_arg);
- if (platform_io.Renderer_SwapBuffers) platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg);
- }
-}
-
void ImGui::DestroyPlatformWindow(ImGuiViewportP* viewport)
{
ImGuiContext& g = *GImGui;
@@ -8058,7 +8417,7 @@ void ImGui::DestroyPlatformWindow(ImGuiViewportP* viewport)
viewport->PlatformHandle = NULL;
viewport->RendererUserData = viewport->PlatformHandle = NULL;
viewport->PlatformWindowCreated = false;
- viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false;
+ viewport->ClearRequestFlags();
}
void ImGui::DestroyPlatformWindows()
@@ -8384,7 +8743,7 @@ static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
}
-static void NavRestoreLayer(int layer)
+static void NavRestoreLayer(ImGuiNavLayer layer)
{
ImGuiContext& g = *GImGui;
g.NavLayer = layer;
@@ -8523,7 +8882,7 @@ static void ImGui::NavUpdate()
ImGuiContext& g = *GImGui;
g.IO.WantSetMousePos = false;
#if 0
- if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
+ if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
#endif
// Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard)
@@ -8611,14 +8970,15 @@ static void ImGui::NavUpdate()
// Set output flags for user application
g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
- g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest;
+ g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
// Process NavCancel input (to close a popup, get back to parent, clear focus)
if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
{
if (g.ActiveId != 0)
{
- ClearActiveID();
+ if (!(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_Cancel)))
+ ClearActiveID();
}
else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow && g.NavWindow != g.NavWindow->RootWindowDockStop)
{
@@ -8636,12 +8996,12 @@ static void ImGui::NavUpdate()
{
// Close open popup/menu
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
- ClosePopupToLevel(g.OpenPopupStack.Size - 1);
+ ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
}
else if (g.NavLayer != 0)
{
// Leave the "menu" layer
- NavRestoreLayer(0);
+ NavRestoreLayer(ImGuiNavLayer_Main);
}
else
{
@@ -8683,7 +9043,7 @@ static void ImGui::NavUpdate()
if (g.NavMoveRequestForward == ImGuiNavForward_None)
{
g.NavMoveDir = ImGuiDir_None;
- g.NavMoveRequestFlags = 0;
+ g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
if ((allowed_dir_flags & (1<DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
{
@@ -9026,8 +9386,8 @@ static void ImGui::NavUpdateWindowing()
NavInitWindow(apply_focus_window, false);
// If the window only has a menu layer, select it directly
- if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1))
- g.NavLayer = 1;
+ if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
+ g.NavLayer = ImGuiNavLayer_Menu;
// Request OS level focus
if (apply_focus_window->Viewport != previous_viewport && g.PlatformIO.Platform_SetWindowFocus)
@@ -9042,8 +9402,8 @@ static void ImGui::NavUpdateWindowing()
// Move to parent menu if necessary
ImGuiWindow* new_nav_window = g.NavWindow;
while (new_nav_window->ParentWindow
- && (new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0
- && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
+ && (new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0
+ && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
&& (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
new_nav_window = new_nav_window->ParentWindow;
if (new_nav_window != g.NavWindow)
@@ -9056,10 +9416,10 @@ static void ImGui::NavUpdateWindowing()
g.NavDisableMouseHover = true;
// When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID. It however persist on docking tab tabs.
- const int new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0;
+ const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL);
- if (new_nav_layer == 1 && !preserve_layer_1_nav_id)
- g.NavWindow->NavLastIds[1] = 0;
+ if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id)
+ g.NavWindow->NavLastIds[ImGuiNavLayer_Menu] = 0;
NavRestoreLayer(new_nav_layer);
}
}
@@ -9438,7 +9798,7 @@ void ImGui::ClearDragDrop()
ImGuiContext& g = *GImGui;
g.DragDropActive = false;
g.DragDropPayload.Clear();
- g.DragDropAcceptFlags = 0;
+ g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
g.DragDropAcceptFrameCount = -1;
@@ -9506,7 +9866,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
else
{
window = NULL;
- source_id = ImHash("#SourceExtern", 0);
+ source_id = ImHashStr("#SourceExtern", 0);
source_drag_active = true;
}
@@ -9529,9 +9889,9 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
{
// Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
- // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
+ // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
BeginTooltip();
- if (g.DragDropActive && g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
+ if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
{
ImGuiWindow* tooltip_window = g.CurrentWindow;
tooltip_window->SkipItems = true;
@@ -9732,7 +10092,7 @@ void ImGui::EndDragDropTarget()
// Docking: ImGuiDockNode
// Docking: ImGuiDockNode Tree manipulation functions
// Docking: Public Functions (SetWindowDock, DockSpace)
-// Docking: Public Builder Functions
+// Docking: Builder Functions
// Docking: Begin/End Functions (called from Begin/End)
// Docking: Settings
//-----------------------------------------------------------------------------
@@ -9832,9 +10192,9 @@ namespace ImGui
static void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
static void DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx);
static ImGuiDockNode* DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
- static void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_refs); // Set root_id==0 to clear all
+ static void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_refs); // Use root_id==0 to clear all
static void DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count);
- static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all
+ static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all
// ImGuiDockNode
static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar);
@@ -9864,10 +10224,11 @@ namespace ImGui
static void DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size);
static void DockNodeTreeUpdateSplitter(ImGuiDockNode* node);
static ImGuiDockNode* DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos);
+ static ImGuiDockNode* DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node);
// Settings
- static void DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id);
- static void DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count);
+ static void DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id);
+ static void DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count);
static ImGuiDockNodeSettings* DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id);
static void* DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
static void DockSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
@@ -9881,8 +10242,8 @@ namespace ImGui
// or we always hold the entire docking node tree. Nodes are frequently hidden, e.g. if the window(s) or child nodes they host are not active.
// At boot time only, we run a simple GC to remove nodes that have no references.
// Because dock node settings (which are small, contiguous structures) are always mirrored by their corresponding dock nodes (more complete structures),
-// we can also very easily recreate the nodes from scratch given the settings data (this is what DockContextRebuild() does).
-// This is convenient as docking reconfiguration can be implemented by mostly poking at the simpler setttings data.
+// we can also very easily recreate the nodes from scratch given the settings data (this is what DockContextRebuild() does).
+// This is convenient as docking reconfiguration can be implemented by mostly poking at the simpler settings data.
//-----------------------------------------------------------------------------
void ImGui::DockContextInitialize(ImGuiContext* ctx)
@@ -9894,7 +10255,7 @@ void ImGui::DockContextInitialize(ImGuiContext* ctx)
// Add .ini handle for persistent docking data
ImGuiSettingsHandler ini_handler;
ini_handler.TypeName = "Docking";
- ini_handler.TypeHash = ImHash("Docking", 0, 0);
+ ini_handler.TypeHash = ImHashStr("Docking", 0, 0);
ini_handler.ReadOpenFn = DockSettingsHandler_ReadOpen;
ini_handler.ReadLineFn = DockSettingsHandler_ReadLine;
ini_handler.WriteAllFn = DockSettingsHandler_WriteAll;
@@ -9949,8 +10310,9 @@ void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx)
DockContextClearNodes(ctx, 0, true);
return;
}
- if (g.IO.ConfigFlags & ImGuiConfigFlags_DockingNoSplit)
- {
+
+ // Setting NoSplit at runtime merges all nodes
+ if (g.IO.ConfigDockingNoSplit)
for (int n = 0; n < dc->Nodes.Data.Size; n++)
if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
if (node->IsRootNode() && node->IsSplitNode())
@@ -9958,8 +10320,8 @@ void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx)
DockBuilderRemoveNodeChildNodes(node->ID);
//dc->WantFullRebuild = true;
}
- }
-
+
+ // Process full rebuild
#if 0
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
dc->WantFullRebuild = true;
@@ -9970,7 +10332,7 @@ void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx)
dc->WantFullRebuild = false;
}
- // Process Undocking requests (we need to process them _before_ the UpdateMouseMovingWindow call in NewFrame)
+ // Process Undocking requests (we need to process them _before_ the UpdateMouseMovingWindowNewFrame call in NewFrame)
for (int n = 0; n < dc->Requests.Size; n++)
{
ImGuiDockRequest* req = &dc->Requests[n];
@@ -9999,16 +10361,10 @@ void ImGui::DockContextNewFrameUpdateDocking(ImGuiContext* ctx)
// We can have NULL pointers when we delete nodes, but because ID are recycled this should amortize nicely (and our node count will never be very high)
for (int n = 0; n < dc->Nodes.Data.Size; n++)
if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
- if (!node->IsDockSpace && node->IsRootNode())
+ if (node->IsRootNode() && !node->IsDockSpace())
DockNodeUpdate(node);
}
-// Docking context update function, called by EndFrame()
-void ImGui::DockContextEndFrame(ImGuiContext* ctx)
-{
- (void)ctx;
-}
-
static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id)
{
return (ImGuiDockNode*)ctx->DockContext->Nodes.GetVoidPtr(id);
@@ -10017,7 +10373,7 @@ static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID
static ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx)
{
// Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used)
- // FIXME-OPT: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster.
+ // FIXME-OPT FIXME-DOCKING: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster.
ImGuiID id = 0x0001;
while (DockContextFindNodeByID(ctx, id) != NULL)
id++;
@@ -10032,7 +10388,6 @@ static ImGuiDockNode* ImGui::DockContextAddNode(ImGuiContext* ctx, ImGuiID id)
else
IM_ASSERT(DockContextFindNodeByID(ctx, id) == NULL);
ImGuiDockNode* node = IM_NEW(ImGuiDockNode)(id);
- node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = true;
ctx->DockContext->Nodes.SetVoidPtr(node->ID, node);
return node;
}
@@ -10075,11 +10430,11 @@ static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const voi
return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a);
}
-// Pre C++0x doesn't allow us to use a local type (without linkage) as template parameter, so we moved this here.
+// Pre C++0x doesn't allow us to use a function-local type (without linkage) as template parameter, so we moved this here.
struct ImGuiDockContextPruneNodeData
{
- int CountWindows, CountChildWindows, CountChildNodes;
- ImGuiID RootID;
+ int CountWindows, CountChildWindows, CountChildNodes;
+ ImGuiID RootID;
ImGuiDockContextPruneNodeData() { CountWindows = CountChildWindows = CountChildNodes = 0; RootID = 0; }
};
@@ -10128,7 +10483,7 @@ static void ImGui::DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx)
remove |= (data_root->CountChildWindows == 0);
if (remove)
{
- DockSettingsRemoveReferencesToNodes(&settings->ID, 1);
+ DockSettingsRemoveNodeReferences(&settings->ID, 1);
settings->ID = 0;
}
}
@@ -10139,23 +10494,24 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc
// Build nodes
for (int node_n = 0; node_n < node_settings_count; node_n++)
{
- ImGuiDockNodeSettings* node_settings = &node_settings_array[node_n];
- if (node_settings->ID == 0)
+ ImGuiDockNodeSettings* settings = &node_settings_array[node_n];
+ if (settings->ID == 0)
continue;
- ImGuiDockNode* node = DockContextAddNode(ctx, node_settings->ID);
- node->ParentNode = node_settings->ParentID ? DockContextFindNodeByID(ctx, node_settings->ParentID) : NULL;
- node->Pos = ImVec2(node_settings->Pos.x, node_settings->Pos.y);
- node->Size = ImVec2(node_settings->Size.x, node_settings->Size.y);
- node->SizeRef = ImVec2(node_settings->SizeRef.x, node_settings->SizeRef.y);
+ ImGuiDockNode* node = DockContextAddNode(ctx, settings->ID);
+ node->ParentNode = settings->ParentID ? DockContextFindNodeByID(ctx, settings->ParentID) : NULL;
+ node->Pos = ImVec2(settings->Pos.x, settings->Pos.y);
+ node->Size = ImVec2(settings->Size.x, settings->Size.y);
+ node->SizeRef = ImVec2(settings->SizeRef.x, settings->SizeRef.y);
if (node->ParentNode && node->ParentNode->ChildNodes[0] == NULL)
node->ParentNode->ChildNodes[0] = node;
else if (node->ParentNode && node->ParentNode->ChildNodes[1] == NULL)
node->ParentNode->ChildNodes[1] = node;
- node->SelectedTabID = node_settings->SelectedTabID;
- node->SplitAxis = node_settings->SplitAxis;
- node->IsDockSpace = node_settings->IsDockSpace != 0;
- node->IsCentralNode = node_settings->IsCentralNode != 0;
- node->IsHiddenTabBar = node_settings->IsHiddenTabBar != 0;
+ node->SelectedTabID = settings->SelectedTabID;
+ node->SplitAxis = settings->SplitAxis;
+ if (settings->IsDockSpace)
+ node->Flags |= ImGuiDockNodeFlags_Dockspace;
+ node->IsCentralNode = settings->IsCentralNode != 0;
+ node->IsHiddenTabBar = settings->IsHiddenTabBar != 0;
// Bind host window immediately if it already exist (in case of a rebuild)
// This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set.
@@ -10177,10 +10533,10 @@ void ImGui::DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id
if (window->DockNode != NULL)
continue;
- ImGuiDockNode* dock_node = DockContextFindNodeByID(ctx, window->DockId);
- IM_ASSERT(dock_node != NULL); // This should have been called after DockContextBuildNodesFromSettings()
- if (root_id == 0 || DockNodeGetRootNode(dock_node)->ID == root_id)
- DockNodeAddWindow(dock_node, window, true);
+ ImGuiDockNode* node = DockContextFindNodeByID(ctx, window->DockId);
+ IM_ASSERT(node != NULL); // This should have been called after DockContextBuildNodesFromSettings()
+ if (root_id == 0 || DockNodeGetRootNode(node)->ID == root_id)
+ DockNodeAddWindow(node, window, true);
}
}
@@ -10190,6 +10546,7 @@ void ImGui::DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id
void ImGui::DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer)
{
+ IM_ASSERT(target != payload);
ImGuiDockRequest req;
req.Type = ImGuiDockRequestType_Dock;
req.DockTargetWindow = target;
@@ -10249,7 +10606,6 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
}
// FIXME-DOCK: When we are trying to dock an existing single-window node into a loose window, transfer Node ID as well
-
if (target_node)
IM_ASSERT(target_node->LastFrameAlive < g.FrameCount);
if (target_node && target_window && target_node == target_window->DockNodeAsHost)
@@ -10274,18 +10630,11 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
{
// Split into one, one side will be our payload node unless we are dropping a loose window
const ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
- const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0;
+ const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0; // Current contents will be moved to the opposite side
const float split_ratio = req->DockSplitRatio;
DockNodeTreeSplit(ctx, target_node, split_axis, split_inheritor_child_idx, split_ratio, payload_node); // payload_node may be NULL here!
- ImGuiDockNode* inheritor_node = target_node->ChildNodes[split_inheritor_child_idx];
ImGuiDockNode* new_node = target_node->ChildNodes[split_inheritor_child_idx ^ 1];
new_node->HostWindow = target_node->HostWindow;
- if (target_node)
- {
- inheritor_node->IsCentralNode = target_node->IsCentralNode;
- inheritor_node->IsHiddenTabBar = target_node->IsHiddenTabBar;
- target_node->IsCentralNode = false;
- }
target_node = new_node;
}
target_node->IsHiddenTabBar = false;
@@ -10297,7 +10646,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
{
target_node->TabBar = IM_NEW(ImGuiTabBar)();
for (int n = 0; n < target_node->Windows.Size; n++)
- TabBarAddTab(target_node->TabBar, target_node->Windows[n], ImGuiTabItemFlags_None);
+ TabBarAddTab(target_node->TabBar, ImGuiTabItemFlags_None, target_node->Windows[n]);
}
if (payload_node != NULL)
@@ -10316,8 +10665,17 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
IM_ASSERT(visible_node->TabBar->Tabs.Size > 0);
DockNodeMoveWindows(target_node, visible_node);
DockNodeMoveWindows(visible_node, target_node);
- DockSettingsMoveDockReferencesInInactiveWindow(target_node->ID, visible_node->ID);
+ DockSettingsRenameNodeReferences(target_node->ID, visible_node->ID);
+ }
+ if (target_node->IsCentralNode)
+ {
+ // Central node property needs to be moved to a leaf node, pick the last focused one.
+ ImGuiDockNode* last_focused_node = DockContextFindNodeByID(ctx, payload_node->LastFocusedNodeID);
+ IM_ASSERT(last_focused_node != NULL && DockNodeGetRootNode(last_focused_node) == DockNodeGetRootNode(payload_node));
+ last_focused_node->IsCentralNode = true;
+ target_node->IsCentralNode = false;
}
+
IM_ASSERT(target_node->Windows.Size == 0);
DockNodeMoveChildNodes(target_node, payload_node);
}
@@ -10325,7 +10683,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
{
const ImGuiID payload_dock_id = payload_node->ID;
DockNodeMoveWindows(target_node, payload_node);
- DockSettingsMoveDockReferencesInInactiveWindow(payload_dock_id, target_node->ID);
+ DockSettingsRenameNodeReferences(payload_dock_id, target_node->ID);
}
DockContextRemoveNode(ctx, payload_node, true);
}
@@ -10336,7 +10694,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
target_node->VisibleWindow = payload_window;
DockNodeAddWindow(target_node, payload_window, true);
if (payload_dock_id != 0)
- DockSettingsMoveDockReferencesInInactiveWindow(payload_dock_id, target_node->ID);
+ DockSettingsRenameNodeReferences(payload_dock_id, target_node->ID);
}
}
@@ -10364,26 +10722,26 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
IM_ASSERT(node->IsLeafNode());
IM_ASSERT(node->Windows.Size >= 1);
- // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload.
- // Otherwise delete the previous node by merging the other sibling back into the parent node.
if (node->IsRootNode() || node->IsCentralNode)
{
+ // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload.
ImGuiDockNode* new_node = DockContextAddNode(ctx, 0);
DockNodeMoveWindows(new_node, node);
- DockSettingsMoveDockReferencesInInactiveWindow(node->ID, new_node->ID);
+ DockSettingsRenameNodeReferences(node->ID, new_node->ID);
for (int n = 0; n < new_node->Windows.Size; n++)
UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL);
new_node->WantMouseMove = true;
}
else
{
+ // Otherwise delete the previous node by merging the other sibling back into the parent node.
IM_ASSERT(node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node);
int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1;
node->ParentNode->ChildNodes[index_in_parent] = NULL;
DockNodeTreeMerge(ctx, node->ParentNode, node->ParentNode->ChildNodes[index_in_parent ^ 1]);
- node->ParentNode->InitFromFirstWindowViewport = true; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport
+ node->ParentNode->AutorityForViewport = ImGuiDataAutority_Window; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport
node->ParentNode = NULL;
- node->InitFromFirstWindowPosSize = true;
+ node->AutorityForPos = node->AutorityForSize = ImGuiDataAutority_Window;
node->WantMouseMove = true;
}
MarkIniSettingsDirty();
@@ -10407,10 +10765,10 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id)
LastFocusedNodeID = 0;
SelectedTabID = 0;
WantCloseTabID = 0;
- InitFromFirstWindowPosSize = InitFromFirstWindowViewport = false;
+ AutorityForPos = AutorityForSize = AutorityForViewport = ImGuiDataAutority_Auto;
IsVisible = true;
- IsFocused = IsDockSpace = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false;
- WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarToggle = false;
+ IsFocused = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false;
+ WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false;
}
ImGuiDockNode::~ImGuiDockNode()
@@ -10441,6 +10799,7 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL);
node->Windows.push_back(window);
+ node->WantHiddenTabBarUpdate = true;
window->DockNode = node;
window->DockId = node->ID;
window->DockIsActive = (node->Windows.Size > 1);
@@ -10456,8 +10815,15 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
// When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage.
// In particular it is important we init the viewport from the first window so we don't create two viewports and drop one.
- if (node->HostWindow == NULL && !node->IsDockSpace && node->IsRootNode())
- node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = true;
+ if (node->HostWindow == NULL && !node->IsDockSpace() && node->IsRootNode())
+ {
+ if (node->AutorityForPos == ImGuiDataAutority_Auto)
+ node->AutorityForPos = ImGuiDataAutority_Window;
+ if (node->AutorityForSize == ImGuiDataAutority_Auto)
+ node->AutorityForSize = ImGuiDataAutority_Window;
+ if (node->AutorityForViewport == ImGuiDataAutority_Auto)
+ node->AutorityForViewport = ImGuiDataAutority_Window;
+ }
// Add to tab bar if requested
if (add_to_tab_bar)
@@ -10469,9 +10835,9 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
// Add existing windows
for (int n = 0; n < node->Windows.Size - 1; n++)
- TabBarAddTab(node->TabBar, node->Windows[n], ImGuiTabItemFlags_None);
+ TabBarAddTab(node->TabBar, ImGuiTabItemFlags_None, node->Windows[n]);
}
- TabBarAddTab(node->TabBar, window, ImGuiTabItemFlags_Unsorted);
+ TabBarAddTab(node->TabBar, ImGuiTabItemFlags_Unsorted, window);
}
DockNodeUpdateVisibleFlag(node);
@@ -10504,8 +10870,11 @@ static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window
break;
}
IM_ASSERT(erased);
+ if (node->VisibleWindow == window)
+ node->VisibleWindow = NULL;
// Remove tab and possibly tab bar
+ node->WantHiddenTabBarUpdate = true;
if (node->TabBar)
{
TabBarRemoveTab(node->TabBar, window->ID);
@@ -10625,7 +10994,7 @@ struct ImGuiDockNodeUpdateScanResults
ImGuiDockNode* CentralNode;
ImGuiDockNode* FirstNodeWithWindows;
int CountNodesWithWindows;
- //ImGuiDockFamily DockFamilyForMerges;
+ //ImGuiWindowClass WindowClassForMerges;
ImGuiDockNodeUpdateScanResults() { CentralNode = FirstNodeWithWindows = NULL; CountNodesWithWindows = 0; }
};
@@ -10641,6 +11010,7 @@ static void DockNodeUpdateScanRec(ImGuiDockNode* node, ImGuiDockNodeUpdateScanRe
if (node->IsCentralNode)
{
IM_ASSERT(results->CentralNode == NULL); // Should be only one
+ IM_ASSERT(node->IsLeafNode() && "If you get this assert: please submit .ini file + repro of actions leading to this.");
results->CentralNode = node;
}
if (results->CountNodesWithWindows > 1 && results->CentralNode != NULL)
@@ -10659,9 +11029,10 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
IM_ASSERT(node->ParentNode == NULL || node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node);
- // Inherit flags
+ // Inherit most flags
+ ImGuiDockNodeFlags flags_to_inherit = ~0 & ~ImGuiDockNodeFlags_Dockspace;
if (node->ParentNode)
- node->Flags = node->ParentNode->Flags;
+ node->Flags = node->ParentNode->Flags & flags_to_inherit;
// Recurse into children
// There is the possibility that one of our child becoming empty will delete itself and moving its sibling contents into 'node'.
@@ -10696,6 +11067,11 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
window_n--;
}
+ // Auto-hide tab bar option
+ if (node->WantHiddenTabBarUpdate && node->Windows.Size == 1 && (node->Flags & ImGuiDockNodeFlags_AutoHideTabBar) && !node->IsHiddenTabBar)
+ node->WantHiddenTabBarToggle = true;
+ node->WantHiddenTabBarUpdate = false;
+
// Apply toggles at a single point of the frame (here!)
if (node->Windows.Size > 1)
node->IsHiddenTabBar = false;
@@ -10709,7 +11085,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node)
{
// Update visibility flag
- bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsCentralNode;
+ bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace() : node->IsCentralNode;
is_visible |= (node->Windows.Size > 0);
is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible);
is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible);
@@ -10722,7 +11098,7 @@ static void ImGui::DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWind
IM_ASSERT(node->WantMouseMove == true);
ImVec2 backup_active_click_offset = g.ActiveIdClickOffset;
StartMouseMovingWindow(window);
- g.MovingWindow = window; // If we are docked into a non moveable root widnow, StartMouseMovingWindow() won't set g.MovingWindow. OVerride that decision.
+ g.MovingWindow = window; // If we are docked into a non moveable root window, StartMouseMovingWindow() won't set g.MovingWindow. Override that decision.
node->WantMouseMove = false;
g.ActiveIdClickOffset = backup_active_click_offset;
}
@@ -10748,23 +11124,23 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
if (node->LastFocusedNodeID == 0 && results.FirstNodeWithWindows != NULL)
node->LastFocusedNodeID = results.FirstNodeWithWindows->ID;
- // Copy the dock family from of our window so it can be used for proper dock filtering.
- // When node has mixed windows, prioritize the family with the most constraint (CompatibleWithNeutral = false) as the reference to copy.
+ // Copy the window class from of our first window so it can be used for proper dock filtering.
+ // When node has mixed windows, prioritize the class with the most constraint (CompatibleWithClassZero = false) as the reference to copy.
// FIXME-DOCK: We don't recurse properly, this code could be reworked to work from DockNodeUpdateScanRec.
if (ImGuiDockNode* first_node_with_windows = results.FirstNodeWithWindows)
{
- node->DockFamily = first_node_with_windows->Windows[0]->DockFamily;
+ node->WindowClass = first_node_with_windows->Windows[0]->WindowClass;
for (int n = 1; n < first_node_with_windows->Windows.Size; n++)
- if (first_node_with_windows->Windows[n]->DockFamily.CompatibleWithFamilyZero == false)
+ if (first_node_with_windows->Windows[n]->WindowClass.DockingAllowUnclassed == false)
{
- node->DockFamily = first_node_with_windows->Windows[n]->DockFamily;
+ node->WindowClass = first_node_with_windows->Windows[n]->WindowClass;
break;
}
}
}
// Early out for hidden root dock nodes (when all DockId references are in inactive windows, or there is only 1 floating window holding on the DockId)
- if (node->Windows.Size <= 1 && node->IsRootNode() && node->IsLeafNode() && !node->IsDockSpace && !g.IO.ConfigDockingTabBarOnSingleWindows)
+ if (node->Windows.Size <= 1 && node->IsRootNode() && node->IsLeafNode() && !node->IsDockSpace() && !g.IO.ConfigDockingTabBarOnSingleWindows)
{
if (node->Windows.Size == 1)
{
@@ -10789,7 +11165,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
}
DockNodeHideHostWindow(node);
- node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = false;
+ node->AutorityForPos = node->AutorityForSize = node->AutorityForViewport = ImGuiDataAutority_Auto;
node->WantCloseAll = false;
node->WantCloseTabID = 0;
node->HasCloseButton = node->HasCollapseButton = false;
@@ -10802,7 +11178,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
ImGuiWindow* host_window = NULL;
bool beginned_into_host_window = false;
- if (node->IsDockSpace)
+ if (node->IsDockSpace())
{
// [Explicit root dockspace node]
IM_ASSERT(node->HostWindow);
@@ -10825,28 +11201,37 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
if (node->IsRootNode() && node->IsVisible)
{
- if (node->InitFromFirstWindowPosSize && node->Windows.Size > 0)
- {
- ImGuiWindow* init_window = node->Windows[0];
- SetNextWindowPos(init_window->Pos);
- SetNextWindowSize(init_window->SizeFull);
- SetNextWindowCollapsed(init_window->Collapsed);
- }
- else if (node->HostWindow == NULL)
- {
+ ImGuiWindow* ref_window = (node->Windows.Size > 0) ? node->Windows[0] : NULL;
+
+ // Sync Pos
+ if (node->AutorityForPos == ImGuiDataAutority_Window && ref_window)
+ SetNextWindowPos(ref_window->Pos);
+ else if (node->AutorityForPos == ImGuiDataAutority_DockNode)
SetNextWindowPos(node->Pos);
+
+ // Sync Size
+ if (node->AutorityForSize == ImGuiDataAutority_Window && ref_window)
+ SetNextWindowSize(ref_window->SizeFull);
+ else if (node->AutorityForSize == ImGuiDataAutority_DockNode)
SetNextWindowSize(node->Size);
- }
- if (node->InitFromFirstWindowViewport && node->Windows.Size > 0)
- SetNextWindowViewport(node->Windows[0]->ViewportId);
+
+ // Sync Collapsed
+ if (node->AutorityForSize == ImGuiDataAutority_Window && ref_window)
+ SetNextWindowCollapsed(ref_window->Collapsed);
+
+ // Sync Viewport
+ if (node->AutorityForViewport == ImGuiDataAutority_Window && ref_window)
+ SetNextWindowViewport(ref_window->ViewportId);
+
+ SetNextWindowClass(&node->WindowClass);
// Begin into the host window
char window_label[20];
DockNodeGetHostWindowTitle(node, window_label, IM_ARRAYSIZE(window_label));
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_DockNodeHost;
window_flags |= ImGuiWindowFlags_NoFocusOnAppearing;
- window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
- window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse;
+ window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoCollapse;
+ window_flags |= ImGuiWindowFlags_NoTitleBar;
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
Begin(window_label, NULL, window_flags);
@@ -10858,12 +11243,21 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
host_window->DC.CursorPos = host_window->Pos;
node->Pos = host_window->Pos;
node->Size = host_window->Size;
+
+ // We set ImGuiWindowFlags_NoFocusOnAppearing because we don't want the host window to take full focus (e.g. steal NavWindow)
+ // But we still it bring it to the front of display. There's no way to choose this precise behavior via window flags.
+ // One simple case to ponder if: window A has a toggle to create windows B/C/D. Dock B/C/D together, clear the toggle and enable it again.
+ // When reappearing B/C/D will request focus and be moved to the top of the display pile, but they are not linked to the dock host window
+ // during the frame they appear. The dock host window would keep its old display order, and the sorting in EndFrame would move B/C/D back
+ // after the dock host window, losing their top-most status.
+ if (node->HostWindow->Appearing)
+ BringWindowToDisplayFront(node->HostWindow);
}
else if (node->ParentNode)
{
node->HostWindow = host_window = node->ParentNode->HostWindow;
}
- node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = false;
+ node->AutorityForPos = node->AutorityForSize = node->AutorityForViewport = ImGuiDataAutority_Auto;
if (node->WantMouseMove && node->HostWindow)
DockNodeStartMouseMovingWindow(node, node->HostWindow);
}
@@ -10895,9 +11289,9 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
if (central_node_hole_register_hit_test_hole)
{
// Add a little padding to match the "resize from edges" behavior and allow grabbing the splitter easily.
- IM_ASSERT(node->IsDockSpace); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode
+ IM_ASSERT(node->IsDockSpace()); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode
ImRect central_hole(central_node->Pos, central_node->Pos + central_node->Size);
- central_hole.Expand(ImVec2(-RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS, -RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS));
+ central_hole.Expand(ImVec2(-WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, -WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS));
if (central_node_hole && !central_hole.IsInverted())
{
SetWindowHitTestHole(host_window, central_hole.Min, central_hole.Max - central_hole.Min);
@@ -10962,6 +11356,10 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
if (beginned_into_host_window)
End();
}
+
+ // Render outer borders last (after the tab bar)
+ if (node->IsRootNode() && host_window)
+ RenderOuterBorders(host_window);
}
// Compare TabItem nodes given the last known DockOrder (will persist in .ini file as hint), used to sort tabs when multiple tabs are added on the same frame.
@@ -11014,11 +11412,11 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Move ourselves to the Menu layer (so we can be accessed by tapping Alt) + undo SkipItems flag in order to draw over the title bar even if the window is collapsed
bool backup_skip_item = host_window->SkipItems;
- if (!node->IsDockSpace)
+ if (!node->IsDockSpace())
{
host_window->SkipItems = false;
- host_window->DC.NavLayerCurrent++;
- host_window->DC.NavLayerCurrentMask <<= 1;
+ host_window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
+ host_window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
}
PushID(node->ID);
@@ -11032,7 +11430,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Collapse button changes shape and display a list
if (IsPopupOpen("#TabListMenu"))
{
- SetNextWindowPos(ImVec2(node->Pos.x - style.FramePadding.x, node->Pos.y + GetFrameHeight()));
+ // Try to position the menu so it is more likely to stays within the same viewport
+ SetNextWindowPos(ImVec2(node->Pos.x, node->Pos.y + GetFrameHeight()));
if (BeginPopup("#TabListMenu"))
{
is_focused = true;
@@ -11064,7 +11463,6 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
ImRect title_bar_rect = ImRect(node->Pos, node->Pos + ImVec2(node->Size.x, g.FontSize + style.FramePadding.y * 2.0f));
ImU32 title_bar_col = GetColorU32(host_window->Collapsed ? ImGuiCol_TitleBgCollapsed : is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
host_window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window->WindowRounding, ImDrawCornerFlags_Top);
- host_window->DrawList->AddLine(title_bar_rect.GetBL(), title_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.WindowBorderSize);
// Collapse button
if (CollapseButton(host_window->GetID("#COLLAPSE"), title_bar_rect.Min, node))
@@ -11080,7 +11478,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
if (g.NavWindow && g.NavWindow->RootWindowDockStop == window)
tab_bar->SelectedTabId = window->ID;
if (TabBarFindTabByID(tab_bar, window->ID) == NULL)
- TabBarAddTab(tab_bar, window, ImGuiTabItemFlags_Unsorted);
+ TabBarAddTab(tab_bar, ImGuiTabItemFlags_Unsorted, window);
}
// If multiple tabs are appearing on the same frame, sort them based on their persistent DockOrder value
@@ -11103,8 +11501,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Begin tab bar
const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node);
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons);
- tab_bar_flags |= ImGuiTabBarFlags_SaveSettings;
- tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeIsDockSpace : 0);
+ tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode;
if (!host_window->Collapsed && is_focused)
tab_bar_flags |= ImGuiTabBarFlags_IsFocused;
BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags, node);
@@ -11119,7 +11516,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
continue;
if (window->LastFrameActive + 1 >= g.FrameCount || !node_was_active)
{
- ImGuiTabItemFlags tab_item_flags = ImGuiTabItemFlags_DockedWindow;
+ ImGuiTabItemFlags tab_item_flags = 0;
if (window->Flags & ImGuiWindowFlags_UnsavedDocument)
tab_item_flags |= ImGuiTabItemFlags_UnsavedDocument;
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
@@ -11178,6 +11575,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
if (IsMouseClicked(0))
{
focus_tab_id = tab_bar->SelectedTabId;
+
+ // Forward moving request to selected window
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, focus_tab_id))
StartMouseMovingWindow(tab->Window);
}
@@ -11204,26 +11603,26 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
PopID();
// Restore SkipItems flag
- if (!node->IsDockSpace)
+ if (!node->IsDockSpace())
{
- host_window->DC.NavLayerCurrent--;
- host_window->DC.NavLayerCurrentMask >>= 1;
+ host_window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
+ host_window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
host_window->SkipItems = backup_skip_item;
}
}
static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window)
{
- if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext)
+ if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace() && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext)
return false;
- ImGuiDockFamily* host_family = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->DockFamily : &host_window->DockFamily;
- ImGuiDockFamily* payload_family = &payload->DockFamily;
- if (host_family->FamilyId != payload_family->FamilyId)
+ ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass;
+ ImGuiWindowClass* payload_class = &payload->WindowClass;
+ if (host_class->ClassId != payload_class->ClassId)
{
- if (host_family->FamilyId != 0 && host_family->CompatibleWithFamilyZero && payload_family->FamilyId == 0)
+ if (host_class->ClassId != 0 && host_class->DockingAllowUnclassed && payload_class->ClassId == 0)
return true;
- if (payload_family->FamilyId != 0 && payload_family->CompatibleWithFamilyZero && host_family->FamilyId == 0)
+ if (payload_class->ClassId != 0 && payload_class->DockingAllowUnclassed && host_class->ClassId == 0)
return true;
return false;
}
@@ -11252,8 +11651,8 @@ static ImRect ImGui::DockNodeCalcTabBarRect(const ImGuiDockNode* node)
ImRect r = ImRect(node->Pos.x, node->Pos.y, node->Pos.x + node->Size.x, node->Pos.y + (g.FontSize + g.Style.FramePadding.y * 2.0f));
if (node->HasCollapseButton)
r.Min.x += g.Style.FramePadding.x + g.FontSize; // + g.Style.ItemInnerSpacing.x; // <-- Adding ItemInnerSpacing makes the title text moves slightly when in a tab bar. Instead we adjusted RenderArrowDockMenu()
- if (node->HasCloseButton)
- r.Max.x -= g.Style.FramePadding.x + g.FontSize + 1.0f;
+ // In DockNodeUpdateTabBar() we currently display a disabled close button even if there is none.
+ r.Max.x -= g.Style.FramePadding.x + g.FontSize + 1.0f;
return r;
}
@@ -11346,11 +11745,20 @@ static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo
ImGuiContext& g = *GImGui;
IM_ASSERT(g.CurrentWindow == host_window); // Because we rely on font size to calculate tab sizes
+ // There is an edge case when docking into a dockspace which only has inactive nodes.
+ // In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive.
+ // Because the inactive leaf node doesn't have proper pos/size yet, we'll use the root node as reference.
+ ImGuiDockNode* ref_node_for_rect = (host_node && !host_node->IsVisible) ? DockNodeGetRootNode(host_node) : host_node;
+ if (ref_node_for_rect)
+ IM_ASSERT(ref_node_for_rect->IsVisible);
+
+ // Build a tentative future node (reuse same structure because it is practical)
data->FutureNode.HasCloseButton = (host_node ? host_node->HasCloseButton : host_window->HasCloseButton) || (root_payload->HasCloseButton);
data->FutureNode.HasCollapseButton = host_node ? true : ((host_window->Flags & ImGuiWindowFlags_NoCollapse) == 0);
- data->FutureNode.Pos = host_node ? host_node->Pos : host_window->Pos;
- data->FutureNode.Size = host_node ? host_node->Size : host_window->Size;
+ data->FutureNode.Pos = host_node ? ref_node_for_rect->Pos : host_window->Pos;
+ data->FutureNode.Size = host_node ? ref_node_for_rect->Size : host_window->Size;
+ // Figure out here we are allowed to dock
const bool src_is_visibly_splitted = root_payload->DockNodeAsHost && root_payload->DockNodeAsHost->IsSplitNode() && (root_payload->DockNodeAsHost->OnlyNodeWithWindows == NULL);
data->IsCenterAvailable = !is_outer_docking;
if (src_is_visibly_splitted && (!host_node || !host_node->IsEmpty()))
@@ -11359,7 +11767,7 @@ static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo
data->IsCenterAvailable = false;
data->IsSidesAvailable = true;
- if ((host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) || (g.IO.ConfigFlags & ImGuiConfigFlags_DockingNoSplit))
+ if ((host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit)
data->IsSidesAvailable = false;
if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsCentralNode)
data->IsSidesAvailable = false;
@@ -11510,7 +11918,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
}
// Stop after ImGuiDir_None
- if ((host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) || (g.IO.ConfigFlags & ImGuiConfigFlags_DockingNoSplit))
+ if ((host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit)
return;
}
}
@@ -11545,6 +11953,10 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
DockNodeMoveWindows(parent_node->ChildNodes[split_inheritor_child_idx], parent_node);
DockNodeTreeUpdatePosSize(parent_node, parent_node->Pos, parent_node->Size);
+
+ child_inheritor->IsCentralNode = parent_node->IsCentralNode;
+ child_inheritor->IsHiddenTabBar = parent_node->IsHiddenTabBar;
+ parent_node->IsCentralNode = false;
}
void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child)
@@ -11565,15 +11977,15 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
if (child_0)
{
DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
- DockSettingsMoveDockReferencesInInactiveWindow(child_0->ID, parent_node->ID);
+ DockSettingsRenameNodeReferences(child_0->ID, parent_node->ID);
}
if (child_1)
{
DockNodeMoveWindows(parent_node, child_1);
- DockSettingsMoveDockReferencesInInactiveWindow(child_1->ID, parent_node->ID);
+ DockSettingsRenameNodeReferences(child_1->ID, parent_node->ID);
}
DockNodeApplyPosSizeToWindows(parent_node);
- parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false;
+ parent_node->AutorityForPos = parent_node->AutorityForSize = parent_node->AutorityForViewport = ImGuiDataAutority_Auto;
parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
parent_node->IsCentralNode = (child_0 && child_0->IsCentralNode) || (child_1 && child_1->IsCentralNode);
parent_node->IsHiddenTabBar = merge_lead_child->IsHiddenTabBar;
@@ -11737,7 +12149,7 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node)
float cur_size_1 = child_1->Size[axis];
float min_size_0 = resize_limits[0] - child_0->Pos[axis];
float min_size_1 = child_1->Pos[axis] + child_1->Size[axis] - resize_limits[1];
- if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS, RESIZE_WINDOWS_FROM_EDGES_FEEDBACK_TIMER))
+ if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER))
{
if (touching_nodes[0].Size > 0 && touching_nodes[1].Size > 0)
{
@@ -11784,6 +12196,17 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node)
DockNodeTreeUpdateSplitter(child_1);
}
+ImGuiDockNode* ImGui::DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node)
+{
+ if (node->IsLeafNode())
+ return node;
+ if (ImGuiDockNode* leaf_node = DockNodeTreeFindFallbackLeafNode(node->ChildNodes[0]))
+ return leaf_node;
+ if (ImGuiDockNode* leaf_node = DockNodeTreeFindFallbackLeafNode(node->ChildNodes[1]))
+ return leaf_node;
+ return NULL;
+}
+
ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos)
{
if (!node->IsVisible)
@@ -11803,6 +12226,16 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos)
return hovered_node;
if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos))
return hovered_node;
+
+ // There is an edge case when docking into a dockspace which only has inactive nodes (because none of the windows are active)
+ // In this case we need to fallback into any leaf mode, possibly the central node.
+ if (node->IsDockSpace() && node->IsRootNode())
+ {
+ if (node->CentralNode && node->IsLeafNode()) // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first.
+ return node->CentralNode;
+ return DockNodeTreeFindFallbackLeafNode(node);
+ }
+
return NULL;
}
@@ -11831,7 +12264,7 @@ void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond)
dock_id = new_node->CentralNode->ID;
else
dock_id = new_node->LastFocusedNodeID;
- }
+ }
if (window->DockId == dock_id)
return;
@@ -11843,7 +12276,7 @@ void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond)
// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a CentralNode by default.
// The Central Node is always displayed even when empty and shrink/extend according to the requested size of its neighbors.
-void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dockspace_flags, const ImGuiDockFamily* dock_family)
+void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class)
{
ImGuiContext* ctx = GImGui;
ImGuiContext& g = *ctx;
@@ -11858,17 +12291,17 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc
node->IsCentralNode = true;
}
node->Flags = dockspace_flags;
- node->DockFamily = dock_family ? *dock_family : ImGuiDockFamily();
+ node->WindowClass = window_class ? *window_class : ImGuiWindowClass();
// When a Dockspace transitioned form implicit to explicit this may be called a second time
// It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again.
if (node->LastFrameActive == g.FrameCount && !(dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly))
{
- IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID");
- node->IsDockSpace = true;
+ IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID");
+ node->Flags |= ImGuiDockNodeFlags_Dockspace;
return;
}
- node->IsDockSpace = true;
+ node->Flags |= ImGuiDockNodeFlags_Dockspace;
// Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible
if (dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly)
@@ -11921,7 +12354,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc
// The limitation with this call is that your window won't have a menu bar.
// Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function.
// So if you want a menu bar you need to repeat this code manually ourselves. As with advanced other Docking API, we may change this function signature.
-ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiDockFamily* dock_family)
+ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class)
{
if (viewport == NULL)
viewport = GetMainViewport();
@@ -11946,7 +12379,7 @@ ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags
PopStyleVar(3);
ImGuiID dockspace_id = GetID("Dockspace");
- DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags, dock_family);
+ DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags, window_class);
End();
return dockspace_id;
@@ -11961,11 +12394,13 @@ ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags
void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id)
{
- ImGuiID window_id = ImHash(window_name, 0);
+ // We don't preserve relative order of multiple docked windows (by clearing DockOrder back to -1)
+ ImGuiID window_id = ImHashStr(window_name, 0);
if (ImGuiWindow* window = FindWindowByID(window_id))
{
// Apply to created window
SetWindowDock(window, node_id, ImGuiCond_Always);
+ window->DockOrder = -1;
}
else
{
@@ -11974,6 +12409,7 @@ void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id)
if (settings == NULL)
settings = CreateNewWindowSettings(window_name);
settings->DockId = node_id;
+ settings->DockOrder = -1;
}
}
@@ -11983,13 +12419,47 @@ ImGuiDockNode* ImGui::DockBuilderGetNode(ImGuiID node_id)
return DockContextFindNodeByID(ctx, node_id);
}
-void ImGui::DockBuilderAddNode(ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags)
+void ImGui::DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos)
{
ImGuiContext* ctx = GImGui;
- DockSpace(id, ImVec2(0,0), flags | ImGuiDockNodeFlags_KeepAliveOnly);
- ImGuiDockNode* node = DockContextFindNodeByID(ctx, id);
- node->SizeRef = node->Size = ref_size;
- node->LastFrameAlive = -1;
+ ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id);
+ if (node == NULL)
+ return;
+ node->Pos = pos;
+ node->AutorityForPos = ImGuiDataAutority_DockNode;
+}
+
+void ImGui::DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size)
+{
+ ImGuiContext* ctx = GImGui;
+ ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id);
+ if (node == NULL)
+ return;
+ node->Size = node->SizeRef = size;
+ node->AutorityForSize = ImGuiDataAutority_DockNode;
+}
+
+// If you create a regular node, both ref_pos/ref_size will position the window.
+// If you create a dockspace node: ref_pos won't be used, ref_size is useful on the first frame to...
+ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags)
+{
+ ImGuiContext* ctx = GImGui;
+ ImGuiDockNode* node = NULL;
+ if (flags & ImGuiDockNodeFlags_Dockspace)
+ {
+ DockSpace(id, ImVec2(0, 0), flags | ImGuiDockNodeFlags_KeepAliveOnly);
+ node = DockContextFindNodeByID(ctx, id);
+ node->LastFrameAlive = -1;
+ }
+ else
+ {
+ if (id != 0)
+ node = DockContextFindNodeByID(ctx, id);
+ if (!node)
+ node = DockContextAddNode(ctx, id);
+ node->LastFrameAlive = ctx->FrameCount;
+ }
+ return node->ID;
}
void ImGui::DockBuilderRemoveNode(ImGuiID node_id)
@@ -12015,6 +12485,9 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id)
return;
bool has_document_root = false;
+ ImGuiDataAutority backup_root_node_autority_for_pos = root_node ? root_node->AutorityForPos : ImGuiDataAutority_Auto;
+ ImGuiDataAutority backup_root_node_autority_for_size = root_node ? root_node->AutorityForSize : ImGuiDataAutority_Auto;
+
// Process active windows
ImVector nodes_to_remove;
for (int n = 0; n < dc->Nodes.Data.Size; n++)
@@ -12036,7 +12509,10 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id)
// DockNodeMoveWindows->DockNodeAddWindow will normally set those when reaching two windows (which is only adequate during interactive merge)
// Make sure we don't lose our current pos/size. (FIXME-DOCK: Consider tidying up that code in DockNodeAddWindow instead)
if (root_node)
- root_node->InitFromFirstWindowPosSize = false;
+ {
+ root_node->AutorityForPos = backup_root_node_autority_for_pos;
+ root_node->AutorityForSize = backup_root_node_autority_for_size;
+ }
// Apply to settings
for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++)
@@ -12142,7 +12618,6 @@ static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID ds
dst_node->Size = src_node->Size;
dst_node->SizeRef = src_node->SizeRef;
dst_node->SplitAxis = src_node->SplitAxis;
- dst_node->IsDockSpace = src_node->IsDockSpace;
dst_node->IsCentralNode = src_node->IsCentralNode;
out_node_remap_pairs->push_back(src_node->ID);
@@ -12214,7 +12689,7 @@ void ImGui::DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_docks
IM_ASSERT((in_window_remap_pairs->Size % 2) == 0);
// Duplicate entire dock
- // FIXME: When overwriting dst_dockspace_id, windows that aren't part of our dockspace family but that are docked in a same node will be split apart,
+ // FIXME: When overwriting dst_dockspace_id, windows that aren't part of our dockspace window class but that are docked in a same node will be split apart,
// whereas we could attempt to at least keep them together in a new, same floating node.
ImVector node_remap_pairs;
DockBuilderCopyNode(src_dockspace_id, dst_dockspace_id, &node_remap_pairs);
@@ -12226,7 +12701,7 @@ void ImGui::DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_docks
{
const char* src_window_name = (*in_window_remap_pairs)[remap_window_n];
const char* dst_window_name = (*in_window_remap_pairs)[remap_window_n + 1];
- ImGuiID src_window_id = ImHash(src_window_name, 0);
+ ImGuiID src_window_id = ImHashStr(src_window_name, 0);
src_windows.push_back(src_window_id);
// Search in the remapping tables
@@ -12264,10 +12739,10 @@ void ImGui::DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_docks
if (ImGuiID src_dock_id = node_remap_pairs[dock_remap_n])
{
ImGuiID dst_dock_id = node_remap_pairs[dock_remap_n + 1];
- ImGuiDockNode* dock_node = DockBuilderGetNode(src_dock_id);
- for (int window_n = 0; window_n < dock_node->Windows.Size; window_n++)
+ ImGuiDockNode* node = DockBuilderGetNode(src_dock_id);
+ for (int window_n = 0; window_n < node->Windows.Size; window_n++)
{
- ImGuiWindow* window = dock_node->Windows[window_n];
+ ImGuiWindow* window = node->Windows[window_n];
if (src_windows.contains(window->ID))
continue;
@@ -12319,26 +12794,30 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
}
// Bind to our dock node
- ImGuiDockNode* dock_node = window->DockNode;
- if (dock_node != NULL)
- IM_ASSERT(window->DockId == dock_node->ID);
- if (window->DockId != 0 && dock_node == NULL)
+ ImGuiDockNode* node = window->DockNode;
+ if (node != NULL)
+ IM_ASSERT(window->DockId == node->ID);
+ if (window->DockId != 0 && node == NULL)
{
- dock_node = DockContextFindNodeByID(ctx, window->DockId);
+ node = DockContextFindNodeByID(ctx, window->DockId);
// We should not be docking into a split node (SetWindowDock should avoid this)
- if (dock_node && dock_node->IsSplitNode())
+ if (node && node->IsSplitNode())
{
DockContextProcessUndockWindow(ctx, window);
return;
}
// Create node
- if (dock_node == NULL)
- dock_node = DockContextAddNode(ctx, window->DockId);
+ if (node == NULL)
+ {
+ node = DockContextAddNode(ctx, window->DockId);
+ if (auto_dock_node)
+ node->LastFrameAlive = g.FrameCount;
+ }
- DockNodeAddWindow(dock_node, window, true);
- IM_ASSERT(dock_node == window->DockNode);
+ DockNodeAddWindow(node, window, true);
+ IM_ASSERT(node == window->DockNode);
// Fix an edge case with auto-resizing windows: if they are created on the same frame they are creating their dock node,
// we don't want their initial zero-size to spread to the DockNode. We preserve their size.
@@ -12348,7 +12827,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
}
// Undock if the ImGuiDockNodeFlags_NoDockingInCentralNode got set
- if (dock_node->IsCentralNode && (dock_node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode))
+ if (node->IsCentralNode && (node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode))
{
DockContextProcessUndockWindow(ctx, window);
return;
@@ -12356,10 +12835,10 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
// Undock if our dockspace node disappeared
// Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly.
- if (dock_node->LastFrameAlive < g.FrameCount && !auto_dock_node)
+ if (node->LastFrameAlive < g.FrameCount)
{
// If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking()
- ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node);
+ ImGuiDockNode* root_node = DockNodeGetRootNode(node);
if (root_node->LastFrameAlive < g.FrameCount)
{
DockContextProcessUndockWindow(ctx, window);
@@ -12373,34 +12852,34 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
}
// Undock if we are submitted earlier than the host window
- if (dock_node->HostWindow && window->BeginOrderWithinContext < dock_node->HostWindow->BeginOrderWithinContext)
+ if (node->HostWindow && window->BeginOrderWithinContext < node->HostWindow->BeginOrderWithinContext)
{
DockContextProcessUndockWindow(ctx, window);
return;
}
// FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test)
- if (dock_node->HostWindow == NULL)
+ if (node->HostWindow == NULL)
{
window->DockTabIsVisible = false;
return;
}
- IM_ASSERT(dock_node->HostWindow);
- IM_ASSERT(dock_node->IsLeafNode());
+ IM_ASSERT(node->HostWindow);
+ IM_ASSERT(node->IsLeafNode());
// Position window
- SetNextWindowPos(dock_node->Pos);
- SetNextWindowSize(dock_node->Size);
+ SetNextWindowPos(node->Pos);
+ SetNextWindowSize(node->Size);
g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos()
window->DockIsActive = true;
window->DockTabIsVisible = false;
- if (dock_node->Flags & ImGuiDockNodeFlags_KeepAliveOnly)
+ if (node->Flags & ImGuiDockNodeFlags_KeepAliveOnly)
return;
// When the window is selected we mark it as visible.
- if (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID)
+ if (node->TabBar && node->TabBar->VisibleTabId == window->ID)
window->DockTabIsVisible = true;
// When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesForResize.
@@ -12408,22 +12887,22 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
// This is analogous to regular windows being hidden from one frame. It is especially important as nested TabBars would otherwise generate flicker in the form
// of one empty frame.
// Note that we set HiddenFramesForResize=2 because BeginDocked() is called just before Begin() has a chance to decrement the value. Effectively it'll be a 1 frame thing.
- if (!window->DockTabIsVisible && dock_node->TabBar && dock_node->TabBar->NextSelectedTabId == window->ID)
+ if (!window->DockTabIsVisible && node->TabBar && node->TabBar->NextSelectedTabId == window->ID)
window->HiddenFramesForResize = 2;
// Update window flag
IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) == 0);
window->Flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoResize;
- if (dock_node->IsHiddenTabBar)
+ if (node->IsHiddenTabBar)
window->Flags |= ImGuiWindowFlags_NoTitleBar;
else
window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed!
// Save new dock order only if the tab bar is active
- if (dock_node->TabBar)
+ if (node->TabBar)
window->DockOrder = (short)DockNodeGetTabOrder(window);
- if ((dock_node->WantCloseAll || dock_node->WantCloseTabID == window->ID) && p_open != NULL)
+ if ((node->WantCloseAll || node->WantCloseTabID == window->ID) && p_open != NULL)
*p_open = false;
// Update ChildId to allow returning from Child to Parent with Escape
@@ -12480,7 +12959,7 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
else
allow_null_target_node = true; // Dock into a regular window
- const ImRect explicit_target_rect = (target_node && target_node->TabBar) ? target_node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight()));
+ const ImRect explicit_target_rect = (target_node && target_node->TabBar && !target_node->IsHiddenTabBar) ? target_node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight()));
const bool is_explicit_target = g.IO.ConfigDockingWithShift || IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max);
// Preview docking request and find out split direction/ratio
@@ -12503,7 +12982,7 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
DockNodePreviewDockRender(window, target_node, payload_window, &split_outer);
// Queue docking request
- if (split_data && split_data->IsDropAllowed && payload->IsDelivery())
+ if (split_data->IsDropAllowed && payload->IsDelivery())
DockContextQueueDock(ctx, window, split_data->SplitNode, payload_window, split_data->SplitDir, split_data->SplitRatio, split_data == &split_outer);
}
}
@@ -12514,25 +12993,25 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
// Docking: Settings
//-----------------------------------------------------------------------------
-static void ImGui::DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id)
+static void ImGui::DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id)
{
ImGuiContext& g = *GImGui;
for (int window_n = 0; window_n < g.Windows.Size; window_n++)
{
ImGuiWindow* window = g.Windows[window_n];
- if (window->DockId == old_dock_id && window->DockNode == NULL)
- window->DockId = new_dock_id;
+ if (window->DockId == old_node_id && window->DockNode == NULL)
+ window->DockId = new_node_id;
}
for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++) // FIXME-OPT: We could remove this loop by storing the index in the map
{
ImGuiWindowSettings* window_settings = &g.SettingsWindows[settings_n];
- if (window_settings->DockId == old_dock_id)
- window_settings->DockId = new_dock_id;
+ if (window_settings->DockId == old_node_id)
+ window_settings->DockId = new_node_id;
}
}
// Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings
-static void ImGui::DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count)
+static void ImGui::DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count)
{
ImGuiContext& g = *GImGui;
int found = 0;
@@ -12613,7 +13092,7 @@ static void DockSettingsHandler_DockNodeToSettings(ImGuiDockContext* dc, ImGuiDo
node_settings.SelectedTabID = node->SelectedTabID;
node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None;
node_settings.Depth = (char)depth;
- node_settings.IsDockSpace = (char)node->IsDockSpace;
+ node_settings.IsDockSpace = (char)node->IsDockSpace();
node_settings.IsCentralNode = (char)node->IsCentralNode;
node_settings.IsHiddenTabBar = (char)node->IsHiddenTabBar;
node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y);
@@ -12784,7 +13263,7 @@ void ImGui::LogToFile(int max_depth, const char* filename)
IM_ASSERT(g.LogFile == NULL);
g.LogFile = ImFileOpen(filename, "ab");
- if (!g.LogFile)
+ if (g.LogFile == NULL)
{
IM_ASSERT(g.LogFile != NULL); // Consider this an error
return;
@@ -12884,7 +13363,7 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
g.SettingsWindows.push_back(ImGuiWindowSettings());
ImGuiWindowSettings* settings = &g.SettingsWindows.back();
settings->Name = ImStrdup(name);
- settings->ID = ImHash(name, 0);
+ settings->ID = ImHashStr(name, 0);
return settings;
}
@@ -12899,7 +13378,7 @@ ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
{
- if (ImGuiWindowSettings* settings = FindWindowSettings(ImHash(name, 0)))
+ if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name, 0)))
return settings;
return CreateNewWindowSettings(name);
}
@@ -12917,7 +13396,7 @@ void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
{
ImGuiContext& g = *GImGui;
- const ImGuiID type_hash = ImHash(type_name, 0, 0);
+ const ImGuiID type_hash = ImHashStr(type_name, 0);
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
return &g.SettingsHandlers[handler_n];
@@ -13022,7 +13501,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
{
- ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHash(name, 0));
+ ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name, 0));
if (!settings)
settings = ImGui::CreateNewWindowSettings(name);
return (void*)settings;
@@ -13041,7 +13520,7 @@ static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*,
else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); }
else if (sscanf(line, "DockId=0x%X,%d", &u1, &i) == 2) { settings->DockId = u1; settings->DockOrder = (short)i; }
else if (sscanf(line, "DockId=0x%X", &u1) == 1) { settings->DockId = u1; settings->DockOrder = -1; }
- else if (sscanf(line, "DockFamilyId=0x%X", &u1) == 1) { settings->DockFamilyId = u1; }
+ else if (sscanf(line, "ClassId=0x%X", &u1) == 1) { settings->ClassId = u1; }
}
static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
@@ -13059,7 +13538,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting
if (!settings)
{
settings = ImGui::CreateNewWindowSettings(window->Name);
- window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings);
+ window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
}
IM_ASSERT(settings->ID == window->ID);
settings->Pos = window->Pos - window->ViewportPos;
@@ -13068,7 +13547,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting
settings->ViewportPos = window->ViewportPos;
IM_ASSERT(window->DockNode == NULL || window->DockNode->ID == window->DockId);
settings->DockId = window->DockId;
- settings->DockFamilyId = window->DockFamily.FamilyId;
+ settings->ClassId = window->WindowClass.ClassId;
settings->DockOrder = window->DockOrder;
settings->Collapsed = window->Collapsed;
}
@@ -13099,8 +13578,8 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting
buf->appendf("DockId=0x%08X\n", settings->DockId);
else
buf->appendf("DockId=0x%08X,%d\n", settings->DockId, settings->DockOrder);
- if (settings->DockFamilyId != 0)
- buf->appendf("DockFamilyId=0x%08X\n", settings->DockFamilyId);
+ if (settings->ClassId != 0)
+ buf->appendf("ClassId=0x%08X\n", settings->ClassId);
}
buf->appendf("\n");
}
@@ -13332,7 +13811,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
triangles_pos[n] = v.pos;
- buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
+ buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
}
ImGui::Selectable(buf, false);
if (overlay_draw_list && ImGui::IsItemHovered())
@@ -13406,7 +13885,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
static void NodeViewport(ImGuiViewportP* viewport)
{
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once);
- if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->Window ? viewport->Window->Name : "N/A"))
+ if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A"))
{
ImGuiWindowFlags flags = viewport->Flags;
ImGui::BulletText("Pos: (%.0f,%.0f), Size: (%.0f,%.0f), Monitor: %d, DpiScale: %.0f%%", viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, viewport->PlatformMonitor, viewport->DpiScale * 100.0f);
@@ -13433,7 +13912,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
if (g.PlatformIO.Monitors.Size > 0 && ImGui::TreeNode("Monitors", "Monitors (%d)", g.PlatformIO.Monitors.Size))
{
- ImGui::TextWrapped("(When viewports are enabled, imgui optionally uses monitor data to position popup/tooltips so they don't straddle monitors.)");
+ ImGui::TextWrapped("(When viewports are enabled, imgui needs uses monitor data to position popup/tooltips so they don't straddle monitors.)");
for (int i = 0; i < g.PlatformIO.Monitors.Size; i++)
{
const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i];
@@ -13457,7 +13936,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
ImGui::TreePop();
}
- if (ImGui::TreeNode("Docking & Tabs"))
+ if (ImGui::TreeNode("Docking & Tab Bars"))
{
ShowDockingDebug();
ImGui::TreePop();
@@ -13480,7 +13959,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
- ImGui::Text("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport->ID, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport->ID);
+ ImGui::Text("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport->ID, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport ? g.MouseLastHoveredViewport->ID : 0);
ImGui::TreePop();
}
@@ -13518,15 +13997,18 @@ void ImGui::ShowDockingDebug()
if (node->Windows.Size > 0)
open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
else
- open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: split %s (act: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
+ open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %s split (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
if (open)
{
IM_ASSERT(node->ChildNodes[0] == NULL || node->ChildNodes[0]->ParentNode == node);
IM_ASSERT(node->ChildNodes[1] == NULL || node->ChildNodes[1]->ParentNode == node);
ImGui::BulletText("Pos (%.0f,%.0f), Size (%.0f, %.0f) Ref (%.0f, %.0f)",
node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y);
+ ImGui::BulletText("VisibleWindow: 0x%08X %s", node->VisibleWindow ? node->VisibleWindow->ID : 0, node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
+ ImGui::BulletText("SelectedTabID: 0x%08X", node->SelectedTabID);
+ ImGui::BulletText("LastFocusedNodeID: 0x%08X", node->LastFocusedNodeID);
ImGui::BulletText("Flags 0x%02X%s%s%s%s",
- node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "",
+ node->Flags, node->IsDockSpace() ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "",
(GImGui->FrameCount - node->LastFrameAlive < 2) ? ", IsAlive" : "", (GImGui->FrameCount - node->LastFrameActive < 2) ? ", IsActive" : "");
if (node->ChildNodes[0])
NodeDockNode(node->ChildNodes[0], "Child[0]");
@@ -13537,9 +14019,10 @@ void ImGui::ShowDockingDebug()
ImGui::TreePop();
}
}
+
static void NodeTabBar(ImGuiTabBar* tab_bar)
{
- // Previous window list
+ // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
char buf[256];
char* p = buf;
const char* buf_end = buf + IM_ARRAYSIZE(buf);
diff --git a/imgui.h b/imgui.h
index 111d1eba..91646ae6 100644
--- a/imgui.h
+++ b/imgui.h
@@ -1,9 +1,9 @@
-// dear imgui, v1.67 WIP
+// dear imgui, v1.68 WIP
// (headers)
// See imgui.cpp file for documentation.
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
-// Read 'Programmer guide' in imgui.cpp for notes on how to setup ImGui in your codebase.
+// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui
/*
@@ -13,13 +13,14 @@ Index of this file:
// Forward declarations and basic types
// ImGui API (Dear ImGui end-user API)
// Flags & Enumerations
+// ImVector<>
// ImGuiStyle
// ImGuiIO
-// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiDockFamily)
+// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiWindowClass)
// Obsolete functions
-// Helpers (ImVector, ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
+// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData)
-// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont)
+// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
// Platform interface for multi-viewport support (ImGuiPlatformMonitor, ImGuiPlatformIO, ImGuiViewport)
*/
@@ -45,12 +46,11 @@ Index of this file:
// Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens)
-#define IMGUI_VERSION "1.66b"
-#define IMGUI_VERSION_NUM 16602
+#define IMGUI_VERSION "1.68 WIP"
+#define IMGUI_VERSION_NUM 16800
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert))
#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch
#define IMGUI_HAS_DOCK 1 // Docking WIP branch
-#define IMGUI_HAS_TABS 1 // Docking WIP branch
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h)
@@ -75,11 +75,15 @@ Index of this file:
#endif
#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers!
#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++.
+#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
// Warnings
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
#elif defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
@@ -89,21 +93,19 @@ Index of this file:
// Forward declarations and basic types
//-----------------------------------------------------------------------------
-struct ImDrawChannel; // Temporary storage for outputting drawing commands out of order, used by ImDrawList::ChannelsSplit()
-struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call)
-struct ImDrawData; // All draw command lists required to render the frame
+struct ImDrawChannel; // Temporary storage for ImDrawList ot output draw commands out of order, used by ImDrawList::ChannelsSplit()
+struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback)
+struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix.
struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder)
struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself)
-struct ImDrawVert; // A single vertex (20 bytes by default, override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)
+struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)
struct ImFont; // Runtime data for a single font within a parent ImFontAtlas
struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader
struct ImFontConfig; // Configuration data when adding a font or merging fonts
-struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*obsolete* please avoid using)
-#ifndef ImTextureID
-typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp)
-#endif
-struct ImGuiContext; // ImGui context (opaque)
-struct ImGuiDockFamily; // Docking family for dock filtering
+struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset)
+struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data
+struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using)
+struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h)
struct ImGuiIO; // Main configuration and I/O between your application and ImGui
struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use)
struct ImGuiListClipper; // Helper to manually clip large list of items
@@ -114,14 +116,18 @@ struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bou
struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use)
struct ImGuiStorage; // Helper for key->value storage
struct ImGuiStyle; // Runtime data for styling/colors
-struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]")
struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder)
+struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]")
struct ImGuiViewport; // Viewport (generally ~1 per window to output to at the OS level. Need per-platform support to use multiple viewports)
+struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform back-end via altered viewport flags and parent/child info)
// Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file)
// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
+#ifndef ImTextureID
+typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp)
+#endif
typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string)
-typedef unsigned short ImWchar; // Character for keyboard input/display
+typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings.
typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling
typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for Set*()
typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type
@@ -233,9 +239,13 @@ namespace ImGui
// Windows
// - Begin() = push window to the stack and start appending to it. End() = pop window from the stack.
// - You may append multiple times to the same window during the same frame.
- // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, which clicking will set the boolean to false when clicked.
- // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window.
- // Always call a matching End() for each Begin() call, regardless of its return value [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.]
+ // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window,
+ // which clicking will set the boolean to false when clicked.
+ // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting
+ // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value!
+ // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc.
+ // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.]
+ // - Note that the bottom of window stack always contains a window called "Debug".
IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
IMGUI_API void End();
@@ -249,6 +259,7 @@ namespace ImGui
IMGUI_API void EndChild();
// Windows Utilities
+ // - "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into.
IMGUI_API bool IsWindowAppearing();
IMGUI_API bool IsWindowCollapsed();
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
@@ -275,6 +286,7 @@ namespace ImGui
IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin()
IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground.
IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id); // set next window viewport
+ IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class (rare/advanced uses: provide hints to the platform back-end via altered viewport flags and parent/child info)
IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
@@ -292,8 +304,8 @@ namespace ImGui
IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y
IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()]
IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()]
- IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
- IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions.
+ IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
+ IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions.
// Parameters stacks (shared)
IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font
@@ -316,7 +328,7 @@ namespace ImGui
IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side)
IMGUI_API void PopItemWidth();
IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position
- IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
+ IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
IMGUI_API void PopTextWrapPos();
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
IMGUI_API void PopAllowKeyboardFocus();
@@ -324,24 +336,26 @@ namespace ImGui
IMGUI_API void PopButtonRepeat();
// Cursor / Layout
+ // - By "cursor" we mean the current output position.
+ // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.
IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
- IMGUI_API void SameLine(float pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally
- IMGUI_API void NewLine(); // undo a SameLine()
- IMGUI_API void Spacing(); // add vertical spacing
- IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size
+ IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates.
+ IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context.
+ IMGUI_API void Spacing(); // add vertical spacing.
+ IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into.
IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0
IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0
- IMGUI_API void BeginGroup(); // lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
- IMGUI_API void EndGroup();
- IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position
- IMGUI_API float GetCursorPosX(); // "
- IMGUI_API float GetCursorPosY(); // "
- IMGUI_API void SetCursorPos(const ImVec2& local_pos); // "
- IMGUI_API void SetCursorPosX(float x); // "
- IMGUI_API void SetCursorPosY(float y); // "
- IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position
- IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in screen coordinates [0..io.DisplaySize] (or [io.ViewportPos..io.ViewportPos + io.ViewportSize] when using multiple viewport). useful to work with ImDrawList API.
- IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in screen coordinates [0..io.DisplaySize] (or [io.ViewportPos..io.ViewportPos + io.ViewportSize] when using multiple viewport)
+ IMGUI_API void BeginGroup(); // lock horizontal starting position
+ IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
+ IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position)
+ IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc.
+ IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList::
+ IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system.
+ IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.)
+ IMGUI_API void SetCursorPosY(float local_y); //
+ IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates
+ IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates (0..io.DisplaySize) or natural OS coordinates when using multiple viewport. Useful to work with ImDrawList API.
+ IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates (0..io.DisplaySize) or natural OS coordinates when using multiple viewport.
IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item)
IMGUI_API float GetTextLineHeight(); // ~ FontSize
IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text)
@@ -349,16 +363,17 @@ namespace ImGui
IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets)
// ID stack/scopes
- // Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most
- // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
- // You can also use the "##foobar" syntax within widget label to distinguish them from each others.
- // In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID,
- // whereas "str_id" denote a string that is only used as an ID and not aimed to be displayed.
- IMGUI_API void PushID(const char* str_id); // push identifier into the ID stack. IDs are hash of the entire stack!
- IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end);
- IMGUI_API void PushID(const void* ptr_id);
- IMGUI_API void PushID(int int_id);
- IMGUI_API void PopID();
+ // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most
+ // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
+ // - The resulting ID are hashes of the entire stack.
+ // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others.
+ // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID,
+ // whereas "str_id" denote a string that is only used as an ID and not normally displayed.
+ IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string).
+ IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string).
+ IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer).
+ IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer).
+ IMGUI_API void PopID(); // pop from the ID stack.
IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself
IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end);
IMGUI_API ImGuiID GetID(const void* ptr_id);
@@ -379,7 +394,7 @@ namespace ImGui
IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1);
// Widgets: Main
- // Most widgets return true when the value has been changed or when pressed/selected
+ // - Most widgets return true when the value has been changed or when pressed/selected
IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button
IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text
IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)
@@ -394,18 +409,19 @@ namespace ImGui
IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses
// Widgets: Combo Box
- // The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items.
- // The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose.
+ // - The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items.
+ // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose.
IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true!
IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1);
IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0"
IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1);
- // Widgets: Drags (tip: ctrl+click on a drag box to input with keyboard. manually input values aren't clamped, can go off-bounds)
- // For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
- // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
- // Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
+ // Widgets: Drags
+ // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
+ // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
+ // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
+ // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound
IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
@@ -419,8 +435,9 @@ namespace ImGui
IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f);
IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f);
- // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds)
- // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
+ // Widgets: Sliders
+ // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
+ // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders
IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
@@ -437,23 +454,24 @@ namespace ImGui
IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f);
// Widgets: Input with Keyboard
- // If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h
+ // - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h
+ // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc.
IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
- IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0);
+ IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
// Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.)
- // Note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x
+ // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x
IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);
IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0);
IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);
@@ -462,7 +480,7 @@ namespace ImGui
IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls.
// Widgets: Trees
- // TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents.
+ // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents.
IMGUI_API bool TreeNode(const char* label);
IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to completely decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet().
IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // "
@@ -483,10 +501,13 @@ namespace ImGui
IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header
// Widgets: Selectables
+ // - A selectable highlights when hovered, and can display another color when selected.
+ // - Neighbors selectable extend their highlight bounds in order to leave no gap between them.
IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
// Widgets: List Boxes
+ // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them.
IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1);
IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards.
@@ -499,7 +520,8 @@ namespace ImGui
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
IMGUI_API void PlotHistogram(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));
- // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace)
+ // Widgets: Value() Helpers.
+ // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace)
IMGUI_API void Value(const char* prefix, bool b);
IMGUI_API void Value(const char* prefix, int v);
IMGUI_API void Value(const char* prefix, unsigned int v);
@@ -521,7 +543,14 @@ namespace ImGui
IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip().
IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1);
- // Popups
+ // Popups, Modals
+ // The properties of popups windows are:
+ // - They block normal mouse hovering detection outside them. (*)
+ // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
+ // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
+ // User can manipulate the visibility state by calling OpenPopup().
+ // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
+ // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true!
IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
@@ -530,11 +559,12 @@ namespace ImGui
IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside)
IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true!
IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened.
- IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open
+ IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current begin-ed level of the popup stack.
IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup.
// Columns
- // You can also use SameLine(pos_x) for simplified columns. The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!)
+ // - You can also use SameLine(pos_x) to mimic simplified columns.
+ // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!)
IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true);
IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished
IMGUI_API int GetColumnIndex(); // get current column index
@@ -544,10 +574,11 @@ namespace ImGui
IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column
IMGUI_API int GetColumnsCount();
- // Tabs
+ // Tab Bars, Tabs
+ // [BETA API] API may evolve!
// Note: Tabs are automatically created by the docking system. Use this to create tab bars/tabs yourself without docking being involved.
IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar
- IMGUI_API void EndTabBar();
+ IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true!
IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected.
IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true!
IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
@@ -557,15 +588,16 @@ namespace ImGui
// Note: you DO NOT need to call DockSpace() to use most Docking facilities!
// To dock windows: hold SHIFT anywhere while moving windows (if io.ConfigDockingWithShift == true) or drag windows from their title bar (if io.ConfigDockingWithShift = false)
// Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details.
- IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiDockFamily* dock_family = NULL);
- IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags dockspace_flags = 0, const ImGuiDockFamily* dock_family = NULL);
- IMGUI_API void SetNextWindowDockId(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK)
- IMGUI_API void SetNextWindowDockFamily(const ImGuiDockFamily* dock_family); // set next window user type (docking filters by same user_type)
- IMGUI_API ImGuiID GetWindowDockId();
+ IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL);
+ IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags dockspace_flags = 0, const ImGuiWindowClass* window_class = NULL);
+ IMGUI_API void SetNextWindowDockID(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK)
+ IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class / user type (docking filters by same user_type)
+ IMGUI_API ImGuiID GetWindowDockID();
IMGUI_API bool IsWindowDocked(); // is current window docked into another window?
- // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging.
- IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty
+ // Logging/Capture
+ // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging.
+ IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty (stdout)
IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file
IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard
IMGUI_API void LogFinish(); // stop logging (close file, etc.)
@@ -573,7 +605,7 @@ namespace ImGui
IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed)
// Drag and Drop
- // [BETA API] Missing Demo code. API may evolve.
+ // [BETA API] API may evolve!
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource()
IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t size, ImGuiCond cond = 0);// type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui.
IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true!
@@ -581,18 +613,19 @@ namespace ImGui
IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released.
IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.
-
+
// Clipping
IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
IMGUI_API void PopClipRect();
// Focus, Activation
- // (Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item")
+ // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item"
IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window.
IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.
// Item/Widgets Utilities
- // See Demo Window under "Widgets->Querying Status" for an interactive visualization of many of those functions.
+ // - Most of the functions are referring to the last/previous item we submitted.
+ // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions.
IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options.
IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false)
IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation?
@@ -604,16 +637,16 @@ namespace ImGui
IMGUI_API bool IsAnyItemHovered();
IMGUI_API bool IsAnyItemActive();
IMGUI_API bool IsAnyItemFocused();
- IMGUI_API ImVec2 GetItemRectMin(); // get bounding rectangle of last item, in screen space
- IMGUI_API ImVec2 GetItemRectMax(); // "
- IMGUI_API ImVec2 GetItemRectSize(); // get size of last item, in screen space
+ IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space)
+ IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space)
+ IMGUI_API ImVec2 GetItemRectSize(); // get size of last item
IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area.
// Miscellaneous Utilities
IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side.
- IMGUI_API double GetTime();
- IMGUI_API int GetFrameCount();
+ IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame.
+ IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame.
IMGUI_API ImDrawList* GetOverlayDrawList(); // get overlay draw list for the viewport associated to the current window. this draw list will be the last rendered. useful to quickly draw overlays shapes/text.
IMGUI_API ImDrawList* GetOverlayDrawList(ImGuiViewport* viewport); // get overlay draw list for the given viewport.
IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances
@@ -643,33 +676,33 @@ namespace ImGui
IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime.
IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down)
IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold
- IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.
+ IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.
IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); //
IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into
- IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount since clicking. if lock_threshold < -1.0f uses io.MouseDraggingThreshold
+ IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position. This is locked and return 0.0f until the mouse moves past a distance threshold at least once. If lock_threshold < -1.0f uses io.MouseDraggingThreshold
IMGUI_API void ResetMouseDragDelta(int button = 0); //
IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type
- IMGUI_API void CaptureKeyboardFromApp(bool capture = true); // manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered.
- IMGUI_API void CaptureMouseFromApp(bool capture = true); // manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle).
+ IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call.
+ IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call.
// Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard)
IMGUI_API const char* GetClipboardText();
IMGUI_API void SetClipboardText(const char* text);
// Settings/.Ini Utilities
- // The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini").
- // Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.
+ // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini").
+ // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.
IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).
IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename);
IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings.
// Memory Utilities
- // All those functions are not reliant on the current context.
- // If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again.
- IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL);
+ // - All those functions are not reliant on the current context.
+ // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again.
+ IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);
IMGUI_API void* MemAlloc(size_t size);
IMGUI_API void MemFree(void* ptr);
@@ -680,6 +713,7 @@ namespace ImGui
IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport.
IMGUI_API void RenderPlatformWindowsDefault(void* platform_arg = NULL, void* renderer_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport. may be reimplemented by user for custom rendering needs.
IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from back-end Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext().
+ IMGUI_API ImGuiViewport* FindViewportByID(ImGuiID id); // this is a helper for back-ends.
IMGUI_API ImGuiViewport* FindViewportByPlatformHandle(void* platform_handle); // this is a helper for back-ends. the type platform_handle is decided by the back-end (e.g. HWND, MyWindow*, GLFWwindow* etc.)
} // namespace ImGui
@@ -729,7 +763,7 @@ enum ImGuiWindowFlags_
// [Obsolete]
//ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f / style.WindowBorderSize=1.0f to enable borders around windows and items
- //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigResizeWindowsFromEdges and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)
+ //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)
};
// Flags for ImGui::InputText()
@@ -818,11 +852,12 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3,
ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4,
- ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 5, // Resize tabs when they don't fit
- ImGuiTabBarFlags_FittingPolicyScroll = 1 << 6, // Add scroll buttons when tabs don't fit
+ ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab
+ ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit
+ ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown
-};
+};
// Flags for ImGui::BeginTabItem()
enum ImGuiTabItemFlags_
@@ -844,7 +879,8 @@ enum ImGuiDockNodeFlags_
ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 3, // Disable docking inside the Central Node, which will be always kept empty.
//ImGuiDockNodeFlags_NoLayoutChanges = 1 << 4, // Disable adding/removing nodes interactively. Useful with programatically setup dockspaces.
ImGuiDockNodeFlags_NoResize = 1 << 5, // Disable resizing child nodes using the splitter/separators. Useful with programatically setup dockspaces.
- ImGuiDockNodeFlags_PassthruDockspace = 1 << 6 // 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background.
+ ImGuiDockNodeFlags_PassthruDockspace = 1 << 6, // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background.
+ ImGuiDockNodeFlags_AutoHideTabBar = 1 << 7 // Tab bar will automatically hide when there is a single window in the dock node.
};
// Flags for ImGui::IsWindowFocused()
@@ -995,16 +1031,12 @@ enum ImGuiConfigFlags_
// [BETA] Docking
ImGuiConfigFlags_DockingEnable = 1 << 6, // Docking enable flags. Use SHIFT to dock window into another (or without SHIFT if io.ConfigDockingWithShift = false).
- ImGuiConfigFlags_DockingNoSplit = 1 << 7, // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.
// [BETA] Viewports
// When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable.
ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends)
- ImGuiConfigFlags_ViewportsNoTaskBarIcon = 1 << 11, // Disable task bars icons for all secondary viewports (will set ImGuiViewportFlags_NoTaskBarIcon on them)
- ImGuiConfigFlags_ViewportsNoMerge = 1 << 12, // All floating windows will always create their own viewport and platform window.
- ImGuiConfigFlags_ViewportsDecoration = 1 << 13, // FIXME [Broken] Enable platform decoration for all secondary viewports (will not set ImGuiViewportFlags_NoDecoration on them). This currently doesn't behave well in Windows because 1) By default the new window animation get in the way of our transitions, 2) It enable a minimum window size which tends to breaks resizing. You can workaround the later by setting style.WindowMinSize to a bigger value.
- ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 14, // FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). Note that resizing the main window itself is up to your application.
- ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 15, // FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress.
+ ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 14, // [BETA: Don't use] FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). Note that resizing the main window itself is up to your application.
+ ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 15, // [BETA: Don't use] FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress.
// User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui)
ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware.
@@ -1082,8 +1114,9 @@ enum ImGuiCol_
// Obsolete names (will be removed)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg, ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive
- , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg
+ , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63]
+ , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg // [renamed in 1.53]
+ , ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive // [renamed in 1.51]
//ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors.
//ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate.
#endif
@@ -1196,10 +1229,72 @@ enum ImGuiCond_
#endif
};
+//-----------------------------------------------------------------------------
+// Helper: ImVector<>
+// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
+// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
+// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
+// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
+// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
+//-----------------------------------------------------------------------------
+
+template
+struct ImVector
+{
+ int Size;
+ int Capacity;
+ T* Data;
+
+ // Provide standard typedefs but we don't use them ourselves.
+ typedef T value_type;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+
+ // Constructors, destructor
+ inline ImVector() { Size = Capacity = 0; Data = NULL; }
+ inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
+ inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
+ inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
+
+ inline bool empty() const { return Size == 0; }
+ inline int size() const { return Size; }
+ inline int size_in_bytes() const { return Size * (int)sizeof(T); }
+ inline int capacity() const { return Capacity; }
+ inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
+ inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
+
+ inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
+ inline T* begin() { return Data; }
+ inline const T* begin() const { return Data; }
+ inline T* end() { return Data + Size; }
+ inline const T* end() const { return Data + Size; }
+ inline T& front() { IM_ASSERT(Size > 0); return Data[0]; }
+ inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; }
+ inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; }
+ inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; }
+ inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
+
+ inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
+ inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
+ inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
+
+ // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
+ inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
+ inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
+ inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); }
+ inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; }
+ inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; }
+ inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; }
+ inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
+ inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
+ inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; }
+};
+
//-----------------------------------------------------------------------------
// ImGuiStyle
// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame().
-// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values,
+// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values,
// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors.
//-----------------------------------------------------------------------------
@@ -1228,7 +1323,7 @@ struct ImGuiStyle
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
- float TabBorderSize; // Thickness of border around tabs.
+ float TabBorderSize; // Thickness of border around tabs.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered.
ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
@@ -1244,54 +1339,67 @@ struct ImGuiStyle
//-----------------------------------------------------------------------------
// ImGuiIO
-// Communicate most settings and inputs/outputs to Dear ImGui using this structure.
+// Communicate most settings and inputs/outputs to Dear ImGui using this structure.
// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage.
//-----------------------------------------------------------------------------
struct ImGuiIO
{
//------------------------------------------------------------------
- // Configuration (fill once) // Default value:
+ // Configuration (fill once) // Default value
//------------------------------------------------------------------
- ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.
- ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end.
- ImVec2 DisplaySize; // // Main display size, in pixels. Used e.g. to clamp windows positions. This is the default viewport. Use BeginViewport() for other viewports.
- float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
- float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds.
- const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory.
- const char* LogFilename; // = "imgui_log.txt" // Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
- float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds.
- float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels.
- float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging.
- int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state.
- float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.).
- float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds.
- void* UserData; // = NULL // Store your own data for retrieval by callbacks.
-
- ImFontAtlas* Fonts; // // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array.
- float FontGlobalScale; // = 1.0f // Global scale all fonts
- bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
- ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].
- ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
-
- // Miscellaneous configuration options
- bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations.
- bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space)
- bool ConfigDockingTabBarOnSingleWindows;//= false // [BETA] Make every single floating window display within a docking node.
- bool ConfigDockingTransparentPayload; // = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport can be synced. Best used with ImGuiConfigFlags_ViewportsNoMerge.
- bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
- bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
- bool ConfigResizeWindowsFromEdges; // = true // [BETA] Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the ImGuiWindowFlags_ResizeFromAnySide flag)
+ ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.
+ ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end.
+ ImVec2 DisplaySize; // // Main display size, in pixels. Used e.g. to clamp windows positions. This is for the default viewport. Use BeginViewport() for other viewports.
+ float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
+ float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds.
+ const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory.
+ const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
+ float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds.
+ float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels.
+ float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging.
+ int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state.
+ float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.).
+ float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds.
+ void* UserData; // = NULL // Store your own data for retrieval by callbacks.
+
+ ImFontAtlas*Fonts; // // Load, rasterize and pack one or more fonts into a single texture.
+ float FontGlobalScale; // = 1.0f // Global scale all fonts
+ bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
+ ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].
+ ImVec2 DisplayFramebufferScale; // = (1.0f,1.0f) // For hi-dpi/retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
+
+ // Docking options (when ImGuiConfigFlags_DockingEnable is set)
+ bool ConfigDockingNoSplit; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.
+ bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space)
+ bool ConfigDockingTabBarOnSingleWindows; // = false // [BETA] Make every single floating window display within a docking node.
+ bool ConfigDockingTransparentPayload;// = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.
+
+ // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set)
+ bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.
+ bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it.
+ bool ConfigViewportsNoDecoration; // = true // [BETA] Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size).
+ bool ConfigViewportsNoParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows.
+
+ // Miscellaneous options
+ bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations.
+ bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
+ bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
+ bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
+ bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected.
//------------------------------------------------------------------
// Platform Functions
// (the imgui_impl_xxxx back-end files are setting those up for you)
//------------------------------------------------------------------
- // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window)
- const char* BackendPlatformName;
- const char* BackendRendererName;
+ // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff.
+ const char* BackendPlatformName; // = NULL
+ const char* BackendRendererName; // = NULL
+ void* BackendPlatformUserData; // = NULL
+ void* BackendRendererUserData; // = NULL
+ void* BackendLanguageUserData; // = NULL
// Optional: Access OS clipboard
// (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
@@ -1304,7 +1412,7 @@ struct ImGuiIO
// You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this.
void (*RenderDrawListsFn)(ImDrawData* data);
#else
- // This is only here to keep ImGuiIO the same size, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h.
+ // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h.
void* RenderDrawListsFnUnused;
#endif
@@ -1316,58 +1424,58 @@ struct ImGuiIO
bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text.
float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends.
- ImGuiID MouseHoveredViewport; // (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will use a decent heuristic instead.
+ ImGuiID MouseHoveredViewport; // (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows).
bool KeyCtrl; // Keyboard modifier pressed: Control
bool KeyShift; // Keyboard modifier pressed: Shift
bool KeyAlt; // Keyboard modifier pressed: Alt
bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows
bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys).
- ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
- float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame, all values will be cleared back to zero in ImGui::EndFrame)
+ float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Functions
- IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[]
- IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars); // Add new characters into InputCharacters[] from an UTF-8 string
- inline void ClearInputCharacters() { InputCharacters[0] = 0; } // Clear the text input buffer manually
+ IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input
+ IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
+ IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually
//------------------------------------------------------------------
// Output - Retrieve after calling NewFrame()
//------------------------------------------------------------------
- bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.).
- bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.).
- bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active).
- bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled.
- bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself.
- bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.
- bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events).
- float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames
- int MetricsRenderVertices; // Vertices output during last call to Render()
- int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3
- int MetricsRenderWindows; // Number of visible windows
- int MetricsActiveWindows; // Number of active windows
- int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts.
- ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
+ bool WantCaptureMouse; // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.).
+ bool WantCaptureKeyboard; // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.).
+ bool WantTextInput; // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active).
+ bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled.
+ bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. IMPORTANT: You need to clear io.WantSaveIniSettings yourself.
+ bool NavActive; // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.
+ bool NavVisible; // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events).
+ float Framerate; // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames
+ int MetricsRenderVertices; // Vertices output during last call to Render()
+ int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3
+ int MetricsRenderWindows; // Number of visible windows
+ int MetricsActiveWindows; // Number of active windows
+ int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts.
+ ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
//------------------------------------------------------------------
// [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed!
//------------------------------------------------------------------
- ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
- ImVec2 MouseClickedPos[5]; // Position at time of clicking
- double MouseClickedTime[5]; // Time of last click (used to figure out double-click)
- bool MouseClicked[5]; // Mouse button went from !Down to Down
- bool MouseDoubleClicked[5]; // Has mouse button been double-clicked?
- bool MouseReleased[5]; // Mouse button went from Down to !Down
- bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds.
- float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
- float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
- ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
- float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point
- float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed)
- float KeysDownDurationPrev[512]; // Previous duration the key has been down
+ ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
+ ImVec2 MouseClickedPos[5]; // Position at time of clicking
+ double MouseClickedTime[5]; // Time of last click (used to figure out double-click)
+ bool MouseClicked[5]; // Mouse button went from !Down to Down
+ bool MouseDoubleClicked[5]; // Has mouse button been double-clicked?
+ bool MouseReleased[5]; // Mouse button went from Down to !Down
+ bool MouseDownOwned[5]; // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds.
+ float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
+ float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
+ ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
+ float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point
+ float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed)
+ float KeysDownDurationPrev[512]; // Previous duration the key has been down
float NavInputsDownDuration[ImGuiNavInput_COUNT];
float NavInputsDownDurationPrev[ImGuiNavInput_COUNT];
+ ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper.
IMGUI_API ImGuiIO();
};
@@ -1383,7 +1491,7 @@ struct ImGuiIO
// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows
// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration
// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
-// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.
+// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.
struct ImGuiInputTextCallbackData
{
ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only
@@ -1443,18 +1551,22 @@ struct ImGuiPayload
bool IsDelivery() const { return Delivery; }
};
-// [BETA] For SetNextWindowDockFamily() and DockSpace() function
-struct ImGuiDockFamily
+// [BETA] Rarely used / very advanced uses only. Use with SetNextWindowClass() and DockSpace() functions.
+// Provide hints to the platform back-end via altered viewport flags (enable/disable OS decoration, OS task bar icons, etc.) and OS level parent/child relationships.
+struct ImGuiWindowClass
{
- ImGuiID FamilyId; // 0 = unaffiliated
- bool CompatibleWithFamilyZero; // true = can be docked/merged with an unaffiliated window
+ ImGuiID ClassId; // User data. 0 = Default class (unclassed)
+ ImGuiID ParentViewportId; // Hint for the platform back-end. If non-zero, the platform back-end can create a parent<>child relationship between the platform windows. Not conforming back-ends are free to e.g. parent every viewport to the main viewport or not.
+ ImGuiViewportFlags ViewportFlagsOverrideMask; // Viewport flags to override when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis.
+ ImGuiViewportFlags ViewportFlagsOverrideValue; // Viewport flags values to override when a window of this class owns a viewport.
+ bool DockingAllowUnclassed; // true = can be docked/merged with an unclassed window
- ImGuiDockFamily() { FamilyId = 0; CompatibleWithFamilyZero = true; }
- ImGuiDockFamily(ImGuiID family_id, bool compatible_with_family_zero = true) { FamilyId = family_id; CompatibleWithFamilyZero = compatible_with_family_zero; }
+ ImGuiWindowClass() { ClassId = 0; ParentViewportId = 0; ViewportFlagsOverrideMask = ViewportFlagsOverrideValue = 0x00; DockingAllowUnclassed = true; }
};
//-----------------------------------------------------------------------------
// Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details)
+// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead.
//-----------------------------------------------------------------------------
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@@ -1462,17 +1574,17 @@ namespace ImGui
{
// OBSOLETED in 1.66 (from Sep 2018)
static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); }
- // OBSOLETED in 1.63 (from Aug 2018)
+ // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018)
static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); }
- // OBSOLETED in 1.61 (from Apr 2018)
- IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'!
- IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags = 0);
- IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags = 0);
- // OBSOLETED in 1.60 (from Dec 2017)
+ // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018)
+ IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'!
+ IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0);
+ // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018)
static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); }
static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
- static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { (void)on_edge; (void)outward; IM_ASSERT(0); return pos; }
+ static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { IM_UNUSED(on_edge); IM_UNUSED(outward); IM_ASSERT(0); return pos; }
// OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
static inline void ShowTestWindow() { return ShowDemoWindow(); }
static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); }
@@ -1490,7 +1602,7 @@ namespace ImGui
static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); }
}
-typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent
+typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent
typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData;
#endif
@@ -1498,71 +1610,6 @@ typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData;
// Helpers
//-----------------------------------------------------------------------------
-// Helper: Lightweight std::vector<> like class to avoid dragging dependencies (also: Windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug).
-// *Important* Our implementation does NOT call C++ constructors/destructors. This is intentional, we do not require it but you have to be mindful of that. Do _not_ use this class as a std::vector replacement in your code!
-template
-class ImVector
-{
-public:
- int Size;
- int Capacity;
- T* Data;
-
- typedef T value_type;
- typedef value_type* iterator;
- typedef const value_type* const_iterator;
-
- inline ImVector() { Size = Capacity = 0; Data = NULL; }
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
- inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
- inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; }
-
- inline bool empty() const { return Size == 0; }
- inline int size() const { return Size; }
- inline int capacity() const { return Capacity; }
- inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
- inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
-
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
- inline iterator begin() { return Data; }
- inline const_iterator begin() const { return Data; }
- inline iterator end() { return Data + Size; }
- inline const_iterator end() const { return Data + Size; }
- inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; }
- inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; }
- inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; }
- inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; }
- inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
-
- inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
- inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
- inline void resize(int new_size,const value_type& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
- inline void reserve(int new_capacity)
- {
- if (new_capacity <= Capacity)
- return;
- value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type));
- if (Data)
- {
- memcpy(new_data, Data, (size_t)Size * sizeof(value_type));
- ImGui::MemFree(Data);
- }
- Data = new_data;
- Capacity = new_capacity;
- }
-
- // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
- inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
- inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
- inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); }
- inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
- inline iterator erase(const_iterator it, const_iterator it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(value_type)); Size -= (int)count; return Data + off; }
- inline iterator erase_unsorted(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(value_type)); Size--; return Data + off; }
- inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
- inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
- inline int index_from_pointer(const_iterator it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; }
-};
-
// Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions.
@@ -1583,15 +1630,15 @@ struct ImGuiOnceUponAFrame
};
// Helper: Macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces.
-#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Will obsolete
-#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf)
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf) // OBSOLETED in 1.51, will remove!
#endif
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
struct ImGuiTextFilter
{
IMGUI_API ImGuiTextFilter(const char* default_filter = "");
- IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build
+ IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build
IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const;
IMGUI_API void Build();
void Clear() { InputBuf[0] = 0; Build(); }
@@ -1631,6 +1678,7 @@ struct ImGuiTextBuffer
void clear() { Buf.clear(); }
void reserve(int capacity) { Buf.reserve(capacity); }
const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; }
+ IMGUI_API void append(const char* str, const char* str_end = NULL);
IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2);
IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2);
};
@@ -1761,7 +1809,7 @@ struct ImColor
// Draw callbacks for advanced uses.
// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,
-// you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state,
+// you can poke into the draw list for that! Draw callback may be useful for example to: A) Change your GPU render state,
// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc.
// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }'
typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
@@ -1886,11 +1934,11 @@ struct ImDrawList
IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0);
// Stateful path API, add points then finish with PathFillConvex() or PathStroke()
- inline void PathClear() { _Path.resize(0); }
+ inline void PathClear() { _Path.Size = 0; }
inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); }
- inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); }
- inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); } // Note: Anti-aliased filling requires points to be in clockwise order.
- inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); PathClear(); }
+ inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); }
+ inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order.
+ inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; }
IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10);
IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle
IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0);
@@ -1944,7 +1992,7 @@ struct ImDrawData
};
//-----------------------------------------------------------------------------
-// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont)
+// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont)
//-----------------------------------------------------------------------------
struct ImFontConfig
@@ -1981,6 +2029,21 @@ struct ImFontGlyph
float U0, V0, U1, V1; // Texture coordinates
};
+// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges().
+// This is essentially a tightly packed of vector of 64k booleans = 8KB storage.
+struct ImFontGlyphRangesBuilder
+{
+ ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
+
+ ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / sizeof(int)); memset(UsedChars.Data, 0, 0x10000 / sizeof(int)); }
+ bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
+ void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
+ void AddChar(ImWchar c) { SetBit(c); } // Add character
+ IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
+ IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
+ IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges
+};
+
enum ImFontAtlasFlags_
{
ImFontAtlasFlags_None = 0,
@@ -1996,13 +2059,13 @@ enum ImFontAtlasFlags_
// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you.
// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples)
-// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API.
+// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API.
// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details.
// Common pitfalls:
-// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the
+// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the
// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data.
// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction.
-// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed,
+// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed,
// - Even though many functions are suffixed with "TTF", OTF data is supported just as well.
// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future!
struct ImFontAtlas
@@ -2023,7 +2086,7 @@ struct ImFontAtlas
// Build atlas, retrieve pixel data.
// User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID().
// The pitch is always = Width * BytesPerPixels (1 or 4)
- // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into
+ // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into
// the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste.
IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions.
IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
@@ -2037,7 +2100,7 @@ struct ImFontAtlas
// Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)
// NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details.
- // NB: Consider using GlyphRangesBuilder to build glyph ranges from textual data.
+ // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data.
IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin
IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters
IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
@@ -2046,19 +2109,6 @@ struct ImFontAtlas
IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters
IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters
- // Helpers to build glyph ranges from text data. Feed your application strings/characters to it then call BuildRanges().
- struct GlyphRangesBuilder
- {
- ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
- GlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); }
- bool GetBit(int n) const { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; }
- void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array
- void AddChar(ImWchar c) { SetBit(c); } // Add character
- IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
- IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
- IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges
- };
-
//-------------------------------------------
// Custom Rectangles/Glyphs API
//-------------------------------------------
@@ -2093,7 +2143,7 @@ struct ImFontAtlas
ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_)
ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
- int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1.
+ int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0.
// [Internal]
// NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
@@ -2107,6 +2157,10 @@ struct ImFontAtlas
ImVector CustomRects; // Rectangles for packing custom texture data into the atlas.
ImVector ConfigData; // Internal data
int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETE 1.67+
+#endif
};
// Font runtime data and rendering
@@ -2115,7 +2169,7 @@ struct ImFont
{
// Members: Hot ~62/78 bytes
float FontSize; // // Height of characters, set during loading (don't change after loading)
- float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale()
+ float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
ImVec2 DisplayOffset; // = (0.f,0.f) // Offset font rendering by xx pixels
ImVector Glyphs; // // All glyphs.
ImVector IndexAdvanceX; // // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI).
@@ -2169,24 +2223,24 @@ struct ImFont
// - if you are new to dear imgui and trying to integrate it into your engine, you should probably ignore this for now.
//-----------------------------------------------------------------------------
-// (Optional) Represent the bounds of each connected monitor/display
-// Dear ImGui only uses this to clamp the position of popups and tooltips so they don't straddle multiple monitors.
+// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI.
+// We use this information for multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors.
struct ImGuiPlatformMonitor
{
ImVec2 MainPos, MainSize; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right)
ImVec2 WorkPos, WorkSize; // (Optional) Coordinates without task bars / side bars / menu bars. imgui uses this to avoid positioning popups/tooltips inside this region.
- float DpiScale;
+ float DpiScale; // 1.0f = 96 DPI
ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0,0); DpiScale = 1.0f; }
};
// (Optional) Setup required only if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) is enabled.
-// Access via ImGui::GetPlatformIO(). This is designed so we can mix and match two imgui_impl_xxxx files, one for
-// the Platform (~window handling), one for Renderer. Custom engine back-ends will often provide both Platform
-// and Renderer interfaces and thus may not need to use all functions.
+// Access via ImGui::GetPlatformIO(). This is designed so we can mix and match two imgui_impl_xxxx files,
+// one for the Platform (~window handling), one for Renderer. Custom engine back-ends will often provide
+// both Platform and Renderer interfaces and so may not need to use all functions.
// Platform functions are typically called before their Renderer counterpart,
// apart from Destroy which are called the other way.
// RenderPlatformWindowsDefault() is that helper that iterate secondary viewports and call, in this order:
-// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers()
+// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers()
// You may skip using RenderPlatformWindowsDefault() and call your draw/swap functions yourself if you need
// specific behavior for your multi-window rendering.
struct ImGuiPlatformIO
@@ -2196,6 +2250,7 @@ struct ImGuiPlatformIO
//------------------------------------------------------------------
// (Optional) Platform functions (e.g. Win32, GLFW, SDL2)
+ // Most of them are called by ImGui::UpdatePlatformWindows() and ImGui::RenderPlatformWindowsDefault().
void (*Platform_CreateWindow)(ImGuiViewport* vp); // Create a new platform window for the given viewport
void (*Platform_DestroyWindow)(ImGuiViewport* vp);
void (*Platform_ShowWindow)(ImGuiViewport* vp); // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them first
@@ -2208,9 +2263,10 @@ struct ImGuiPlatformIO
bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp);
void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* title);
void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // (Optional) Setup window transparency
- void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render (platform side)
+ void (*Platform_UpdateWindow)(ImGuiViewport* vp); // (Optional) Called in UpdatePlatforms(). Optional hook to allow the platform back-end from doing general book-keeping every frame.
+ void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render
void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (platform side)
- float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. IMPORTANT: this will be called _before_ the window is created, in which case the implementation is expected to use the viewport->Pos/Size fields to estimate DPI value.
+ float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI.
void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Called during Begin() every time the viewport we are outputting into changes, so back-end has a chance to swap fonts to adjust style.
void (*Platform_SetImeInputPos)(ImGuiViewport* vp, ImVec2 pos); // (Optional) Set IME (Input Method Editor, e.g. for Asian languages) input position, so text preview appears over the imgui input box.
int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For Renderer to call into Platform code
@@ -2239,23 +2295,25 @@ struct ImGuiPlatformIO
enum ImGuiViewportFlags_
{
ImGuiViewportFlags_None = 0,
- ImGuiViewportFlags_NoDecoration = 1 << 0, // Platform Window: Disable platform decorations: title bar, borders, etc.
- ImGuiViewportFlags_NoFocusOnAppearing = 1 << 1, // Platform Window: Don't take focus when created.
- ImGuiViewportFlags_NoInputs = 1 << 2, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it.
- ImGuiViewportFlags_NoTaskBarIcon = 1 << 3, // Platform Window: Disable platform task bar icon (for popups, menus, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcons if set)
- ImGuiViewportFlags_NoRendererClear = 1 << 4, // Platform Window: Renderer doesn't need to clear the framebuffer ahead.
- ImGuiViewportFlags_TopMost = 1 << 5 // Platform Window: Display on top (for tooltips only)
+ ImGuiViewportFlags_NoDecoration = 1 << 0, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips)
+ ImGuiViewportFlags_NoTaskBarIcon = 1 << 1, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set)
+ ImGuiViewportFlags_NoFocusOnAppearing = 1 << 2, // Platform Window: Don't take focus when created.
+ ImGuiViewportFlags_NoFocusOnClick = 1 << 3, // Platform Window: Don't take focus when clicked on.
+ ImGuiViewportFlags_NoInputs = 1 << 4, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it.
+ ImGuiViewportFlags_NoRendererClear = 1 << 5, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely).
+ ImGuiViewportFlags_TopMost = 1 << 6 // Platform Window: Display on top (for tooltips only)
};
// The viewports created and managed by imgui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport.
struct ImGuiViewport
{
- ImGuiID ID;
- ImGuiViewportFlags Flags;
+ ImGuiID ID; // Unique identifier for the viewport
+ ImGuiViewportFlags Flags; // See ImGuiViewportFlags_
ImVec2 Pos; // Position of viewport both in imgui space and in OS desktop/native space
ImVec2 Size; // Size of viewport in pixel
float DpiScale; // 1.0f = 96 DPI = No extra scale
ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame().
+ ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform back-end to setup a parent/child relationship between platform windows.
void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, frame-buffers etc.)
void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context)
@@ -2264,7 +2322,7 @@ struct ImGuiViewport
bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position)
bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size)
- ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; RendererUserData = PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
+ ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; ParentViewportId = 0; RendererUserData = PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); }
};
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index b74720e4..f001fff2 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -1,24 +1,24 @@
-// dear imgui, v1.67 WIP
+// dear imgui, v1.68 WIP
// (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders
-// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of
-// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team,
+// will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of
+// your game/app! Removing this file from your project is hindering access to documentation for everyone in your team,
// likely leading you to poorer usage of the library.
// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
-// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked,
+// If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked,
// you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference.
// Thank you,
// -Your beloved friend, imgui_demo.cpp (that you won't delete)
-// Message to beginner C/C++ programmers about the meaning of the 'static' keyword:
-// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is
-// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data
+// Message to beginner C/C++ programmers about the meaning of the 'static' keyword:
+// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is
+// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data
// in the same place, to make the demo source code faster to read, faster to write, and smaller in size.
// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant
-// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is
+// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is
// likely going to be stored outside your functions.
/*
@@ -71,6 +71,12 @@ Index of this file:
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
#pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal
#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
+#endif
+#if __has_warning("-Wdouble-promotion")
+#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
+#endif
#if __has_warning("-Wreserved-id-macro")
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
#endif
@@ -339,26 +345,42 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
- ImGui::SameLine(); ShowHelpMarker("Use SHIFT to dock window into another (or without SHIFT if io.ConfigDockingWithShift == false)");
- ImGui::CheckboxFlags("io.ConfigFlags: DockingNoSplit", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_DockingNoSplit);
- ImGui::SameLine(); ShowHelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
+ ImGui::SameLine(); ShowHelpMarker(io.ConfigDockingWithShift ? "[beta] Use SHIFT to dock window into each others." : "[beta] Drag from title bar to dock windows into each others.");
+ if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
+ {
+ ImGui::Indent();
+ ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
+ ImGui::SameLine(); ShowHelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
+ ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
+ ImGui::SameLine(); ShowHelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)");
+ ImGui::Checkbox("io.ConfigDockingTabBarOnSingleWindows", &io.ConfigDockingTabBarOnSingleWindows);
+ ImGui::SameLine(); ShowHelpMarker("Create a docking node and tab-bar on single floating windows.");
+ ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
+ ImGui::SameLine(); ShowHelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.");
+ ImGui::Unindent();
+ }
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
- ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoTaskBarIcon", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoTaskBarIcon);
- ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away).");
- ImGui::CheckboxFlags("io.ConfigFlags: ViewportsDecoration", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsDecoration);
- ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away).");
- ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoMerge", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoMerge);
- ImGui::SameLine(); ShowHelpMarker("All floating windows will always create their own viewport and platform window.");
-
- ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
- ImGui::SameLine(); ShowHelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)");
- ImGui::Checkbox("io.ConfigDockingTabBarOnSingleWindows", &io.ConfigDockingTabBarOnSingleWindows);
- ImGui::SameLine(); ShowHelpMarker("Associate a docking node and tab-bar to sinle floating windows.");
+ ImGui::SameLine(); ShowHelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
+ if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
+ {
+ ImGui::Indent();
+ ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
+ ImGui::SameLine(); ShowHelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
+ ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
+ ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away).");
+ ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
+ ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away).");
+ ImGui::Checkbox("io.ConfigViewportsNoParent", &io.ConfigViewportsNoParent);
+ ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the parenting right away).");
+ ImGui::Unindent();
+ }
+
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting");
- ImGui::Checkbox("io.ConfigResizeWindowsFromEdges [beta]", &io.ConfigResizeWindowsFromEdges);
+ ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
ImGui::SameLine(); ShowHelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback.");
+ ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
ImGui::SameLine(); ShowHelpMarker("Instruct Dear ImGui to render a mouse cursor for you. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
ImGui::TreePop();
@@ -367,6 +389,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::TreeNode("Backend Flags"))
{
+ ShowHelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.");
ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying the back-end flags.
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
@@ -454,7 +477,7 @@ static void ShowDemoWindowWidgets()
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
for (int i = 0; i < 7; i++)
{
- if (i > 0)
+ if (i > 0)
ImGui::SameLine();
ImGui::PushID(i);
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f));
@@ -519,7 +542,7 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n");
static float f0 = 0.001f;
- ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
+ ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
static double d0 = 999999.00000001;
ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
@@ -906,17 +929,19 @@ static void ShowDemoWindowWidgets()
}
if (ImGui::TreeNode("Grid"))
{
- static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true };
- for (int i = 0; i < 16; i++)
+ static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true };
+ for (int i = 0; i < 4*4; i++)
{
ImGui::PushID(i);
if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50)))
{
- int x = i % 4, y = i / 4;
- if (x > 0) selected[i - 1] ^= 1;
- if (x < 3) selected[i + 1] ^= 1;
- if (y > 0) selected[i - 4] ^= 1;
- if (y < 3) selected[i + 4] ^= 1;
+ // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary.
+ int x = i % 4;
+ int y = i / 4;
+ if (x > 0) { selected[i - 1] ^= 1; }
+ if (x < 3 && i < 15) { selected[i + 1] ^= 1; }
+ if (y > 0 && i > 3) { selected[i - 4] ^= 1; }
+ if (y < 3 && i < 12) { selected[i + 4] ^= 1; }
}
if ((i % 4) < 3) ImGui::SameLine();
ImGui::PopID();
@@ -947,7 +972,7 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Multi-line Text Input"))
{
- // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
+ // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
// and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
static bool read_only = false;
static char text[1024*16] =
@@ -982,7 +1007,7 @@ static void ShowDemoWindowWidgets()
static float values[90] = { 0 };
static int values_offset = 0;
static double refresh_time = 0.0;
- if (!animate || refresh_time == 0.0f)
+ if (!animate || refresh_time == 0.0)
refresh_time = ImGui::GetTime();
while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo
{
@@ -1065,16 +1090,18 @@ static void ShowDemoWindowWidgets()
ImGui::Text("Color button with Custom Picker Popup:");
- // Generate a dummy palette
- static bool saved_palette_inited = false;
- static ImVec4 saved_palette[32];
- if (!saved_palette_inited)
+ // Generate a dummy default palette. The palette will persist and can be edited.
+ static bool saved_palette_init = true;
+ static ImVec4 saved_palette[32] = { };
+ if (saved_palette_init)
+ {
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
{
ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
saved_palette[n].w = 1.0f; // Alpha
}
- saved_palette_inited = true;
+ saved_palette_init = false;
+ }
static ImVec4 backup_color;
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
@@ -1087,12 +1114,12 @@ static void ShowDemoWindowWidgets()
}
if (ImGui::BeginPopup("mypicker"))
{
- // FIXME: Adding a drag and drop example here would be perfect!
ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
ImGui::Separator();
ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
ImGui::SameLine();
- ImGui::BeginGroup();
+
+ ImGui::BeginGroup(); // Lock X position
ImGui::Text("Current");
ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40));
ImGui::Text("Previous");
@@ -1108,6 +1135,8 @@ static void ShowDemoWindowWidgets()
if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20)))
color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
+ // Allow user to drop colors into each palette entry
+ // (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop)
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
@@ -1184,15 +1213,15 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Data Types"))
{
// The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double
- // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type,
- // and passing all arguments by address.
+ // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type,
+ // and passing all arguments by address.
// This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types.
- // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it
- // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address
+ // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it
+ // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address
// to the generic function. For example:
- // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
- // {
- // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
+ // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
+ // {
+ // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
// }
// Limits (as helper variables that we can take the address of)
@@ -1387,7 +1416,7 @@ static void ShowDemoWindowWidgets()
static int mode = 0;
if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
- if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
+ if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" };
for (int n = 0; n < IM_ARRAYSIZE(names); n++)
{
@@ -1527,12 +1556,12 @@ static void ShowDemoWindowWidgets()
ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
ImGui::BeginChild("child", ImVec2(0, 50), true);
- ImGui::Text("This is another child window for testing with the _ChildWindows flag.");
+ ImGui::Text("This is another child window for testing the _ChildWindows flag.");
ImGui::EndChild();
if (embed_all_inside_a_child_window)
ImGui::EndChild();
- // Calling IsItemHovered() after begin returns the hovered status of the title bar.
+ // Calling IsItemHovered() after begin returns the hovered status of the title bar.
// This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
// This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
static bool test_window = false;
@@ -1540,7 +1569,7 @@ static void ShowDemoWindowWidgets()
if (test_window)
{
// FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
- // Could we fix this through an ImGuiDockFamily feature? Or an API call to tag our parent as "don't skip items"?
+ // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
ImGui::Begin("Title bar Hovered/Active tests", &test_window);
if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
{
@@ -1564,8 +1593,9 @@ static void ShowDemoWindowLayout()
if (!ImGui::CollapsingHeader("Layout"))
return;
- if (ImGui::TreeNode("Child regions"))
+ if (ImGui::TreeNode("Child windows"))
{
+ ShowHelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
static bool disable_mouse_wheel = false;
static bool disable_menu = false;
ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
@@ -1580,7 +1610,8 @@ static void ShowDemoWindowLayout()
// Child 1: no border, enable horizontal scrollbar
{
- ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 300), false, ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0));
+ ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0);
+ ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags);
for (int i = 0; i < 100; i++)
{
ImGui::Text("%04d: scrollable region", i);
@@ -1596,8 +1627,9 @@ static void ShowDemoWindowLayout()
// Child 2: rounded border
{
+ ImGuiWindowFlags window_flags = (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar);
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
- ImGui::BeginChild("Child2", ImVec2(0, 300), true, (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar));
+ ImGui::BeginChild("Child2", ImVec2(0, 260), true, window_flags);
if (!disable_menu && ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Menu"))
@@ -1619,6 +1651,27 @@ static void ShowDemoWindowLayout()
ImGui::PopStyleVar();
}
+ ImGui::Separator();
+
+ // Demonstrate a few extra things
+ // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
+ // - Using SetCursorPos() to position the child window (because the child window is an item from the POV of the parent window)
+ // You can also call SetNextWindowPos() to position the child window. The parent window will effectively layout from this position.
+ // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window)
+ // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this.
+ {
+ ImGui::SetCursorPosX(50);
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
+ ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None);
+ for (int n = 0; n < 50; n++)
+ ImGui::Text("Some test %d", n);
+ ImGui::EndChild();
+ ImVec2 child_rect_min = ImGui::GetItemRectMin();
+ ImVec2 child_rect_max = ImGui::GetItemRectMax();
+ ImGui::PopStyleColor();
+ ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y);
+ }
+
ImGui::TreePop();
}
@@ -1818,7 +1871,7 @@ static void ShowDemoWindowLayout()
if (ImGui::TreeNode("Groups"))
{
- ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)");
+ ShowHelpMarker("Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.");
ImGui::BeginGroup();
{
ImGui::BeginGroup();
@@ -1862,7 +1915,7 @@ static void ShowDemoWindowLayout()
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)");
+ ShowHelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with 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();
@@ -1917,7 +1970,8 @@ static void ShowDemoWindowLayout()
if (ImGui::TreeNode("Scrolling"))
{
- ImGui::TextWrapped("(Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position.)");
+ ShowHelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position.");
+
static bool track = true;
static int track_line = 50, scroll_to_px = 200;
ImGui::Checkbox("Track", &track);
@@ -1958,8 +2012,7 @@ static void ShowDemoWindowLayout()
if (ImGui::TreeNode("Horizontal Scrolling"))
{
- ImGui::Bullet(); ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.");
- ImGui::Bullet(); ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
+ ShowHelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
static int lines = 7;
ImGui::SliderInt("Lines", &lines, 1, 15);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
@@ -1990,15 +2043,15 @@ static void ShowDemoWindowLayout()
ImGui::EndChild();
ImGui::PopStyleVar(2);
float scroll_x_delta = 0.0f;
- ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine();
+ ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine();
ImGui::Text("Scroll from code"); ImGui::SameLine();
- ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine();
+ ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine();
ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
if (scroll_x_delta != 0.0f)
{
ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window)
ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
- ImGui::End();
+ ImGui::EndChild();
}
ImGui::TreePop();
}
@@ -2007,7 +2060,7 @@ static void ShowDemoWindowLayout()
{
static ImVec2 size(100, 100), offset(50, 20);
ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost.");
- ImGui::DragFloat2("size", (float*)&size, 0.5f, 0.0f, 200.0f, "%.0f");
+ ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
ImGui::TextWrapped("(Click and drag)");
ImVec2 pos = ImGui::GetCursorScreenPos();
ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
@@ -2024,12 +2077,13 @@ static void ShowDemoWindowPopups()
if (!ImGui::CollapsingHeader("Popups & Modal windows"))
return;
- // Popups are windows with a few special properties:
+ // The properties of popups windows are:
// - They block normal mouse hovering detection outside them. (*)
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
// - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
+ // User can manipulate the visibility state by calling OpenPopup().
// (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
- // Those three properties are intimately connected. The library needs to hold their visibility state because it can close popups at any time.
+ // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
// Typical use for regular windows:
// bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End();
@@ -2037,7 +2091,7 @@ static void ShowDemoWindowPopups()
// if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
// With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
- // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
+ // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
if (ImGui::TreeNode("Popups"))
{
@@ -2133,7 +2187,7 @@ static void ShowDemoWindowPopups()
ImGui::Text("(You can also right-click me to the same popup as above.)");
ImGui::OpenPopupOnItemClick("item context menu", 1);
- // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem().
+ // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem().
// BeginPopupContextItem() will use the last item ID as the popup ID.
// In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details)
static char name[32] = "Label1";
@@ -2158,6 +2212,7 @@ static void ShowDemoWindowPopups()
if (ImGui::Button("Delete.."))
ImGui::OpenPopup("Delete?");
+
if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
@@ -2180,17 +2235,32 @@ static void ShowDemoWindowPopups()
if (ImGui::Button("Stacked modals.."))
ImGui::OpenPopup("Stacked 1");
- if (ImGui::BeginPopupModal("Stacked 1"))
+ if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
{
+ if (ImGui::BeginMenuBar())
+ {
+ if (ImGui::BeginMenu("File"))
+ {
+ if (ImGui::MenuItem("Dummy menu item")) {}
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
+
+ // Testing behavior of widgets stacking their own regular popups over the modal.
static int item = 1;
- ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
static float color[4] = { 0.4f,0.7f,0.0f,0.5f };
- ImGui::ColorEdit4("color", color); // This is to test behavior of stacked regular popups over a modal
+ ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
+ ImGui::ColorEdit4("color", color);
if (ImGui::Button("Add another modal.."))
ImGui::OpenPopup("Stacked 2");
- if (ImGui::BeginPopupModal("Stacked 2"))
+
+ // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup.
+ // Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here.
+ bool dummy_open = true;
+ if (ImGui::BeginPopupModal("Stacked 2", &dummy_open))
{
ImGui::Text("Hello from Stacked The Second!");
if (ImGui::Button("Close"))
@@ -2514,9 +2584,9 @@ static void ShowDemoWindowMisc()
// Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
static float f3[3] = { 0.0f, 0.0f, 0.0f };
int focus_ahead = -1;
- if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine();
- if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine();
- if (ImGui::Button("Focus on Z")) focus_ahead = 2;
+ if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
+ if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
+ if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
@@ -2577,7 +2647,11 @@ static void ShowDemoWindowMisc()
void ImGui::ShowAboutWindow(bool* p_open)
{
- ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize);
+ if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
+ {
+ ImGui::End();
+ return;
+ }
ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
ImGui::Separator();
ImGui::Text("By Omar Cornut and all dear imgui contributors.");
@@ -2660,6 +2734,8 @@ void ImGui::ShowAboutWindow(bool* p_open)
ImGui::Text("define: IMGUI_HAS_TABS");
#endif
ImGui::Separator();
+ ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
+ ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
@@ -2668,21 +2744,26 @@ void ImGui::ShowAboutWindow(bool* p_open)
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
- if (io.ConfigFlags & ImGuiConfigFlags_DockingNoSplit) ImGui::Text(" DockingNoSplit");
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
- if (io.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcon) ImGui::Text(" ViewportsNoTaskBarIcon");
- if (io.ConfigFlags & ImGuiConfigFlags_ViewportsNoMerge) ImGui::Text(" ViewportsNoMerge");
- if (io.ConfigFlags & ImGuiConfigFlags_ViewportsDecoration) ImGui::Text(" ViewportsDecoration");
if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports");
if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts");
- if (io.ConfigFlags & ImGuiConfigFlags_IsSRGB) ImGui::Text(" IsSRGB");
- if (io.ConfigFlags & ImGuiConfigFlags_IsTouchScreen) ImGui::Text(" IsTouchScreen");
- if (io.MouseDrawCursor) ImGui::Text(" MouseDrawCursor");
- if (io.ConfigDockingWithShift) ImGui::Text(" ConfigDockingWithShift");
- if (io.ConfigDockingTransparentPayload) ImGui::Text(" ConfigDockingTransparentPayload");
- if (io.ConfigMacOSXBehaviors) ImGui::Text(" ConfigMacOSXBehaviors");
- if (io.ConfigInputTextCursorBlink) ImGui::Text(" ConfigInputTextCursorBlink");
- if (io.ConfigResizeWindowsFromEdges) ImGui::Text(" ConfigResizeWindowsFromEdges");
+ if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
+ if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
+ if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
+ if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
+ if (io.ConfigViewportsNoParent) ImGui::Text("io.ConfigViewportsNoParent");
+ if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
+ if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift");
+ if (io.ConfigDockingTabBarOnSingleWindows) ImGui::Text("io.ConfigDockingTabBarOnSingleWindows");
+ if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
+ if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
+ if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
+ if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
+ if (io.ConfigViewportsNoParent) ImGui::Text("io.ConfigViewportsNoParent");
+ if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
+ if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
+ if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
+ if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
@@ -2690,8 +2771,6 @@ void ImGui::ShowAboutWindow(bool* p_open)
if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
- ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
- ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
ImGui::Separator();
ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
@@ -2792,188 +2871,198 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SameLine();
ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere.");
- if (ImGui::TreeNode("Rendering"))
- {
- ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
- ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
- ImGui::PushItemWidth(100);
- ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f);
- if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
- ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
- ImGui::PopItemWidth();
- ImGui::TreePop();
- }
+ ImGui::Separator();
- if (ImGui::TreeNode("Settings"))
+ if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
{
- ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
- ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f");
- ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
- ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
- ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
- ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
- ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
- ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
- ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
- ImGui::Text("BorderSize");
- ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
- ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
- ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
- ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
- ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
- ImGui::Text("Rounding");
- ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
- ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
- ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
- ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
- ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
- ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
- ImGui::Text("Alignment");
- ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
- ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content.");
- ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
- ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
- ImGui::TreePop();
- }
+ if (ImGui::BeginTabItem("Sizes"))
+ {
+ ImGui::Text("Main");
+ ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f");
+ ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
+ ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
+ ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
+ ImGui::Text("Borders");
+ ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui::Text("Rounding");
+ ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
+ ImGui::Text("Alignment");
+ ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
+ ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content.");
+ ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
+ ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
+ ImGui::EndTabItem();
+ }
- if (ImGui::TreeNode("Colors"))
- {
- static int output_dest = 0;
- static bool output_only_modified = true;
- if (ImGui::Button("Export Unsaved"))
+ if (ImGui::BeginTabItem("Colors"))
{
- if (output_dest == 0)
- ImGui::LogToClipboard();
- else
- ImGui::LogToTTY();
- ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
- for (int i = 0; i < ImGuiCol_COUNT; i++)
+ static int output_dest = 0;
+ static bool output_only_modified = true;
+ if (ImGui::Button("Export Unsaved"))
{
- const ImVec4& col = style.Colors[i];
- const char* name = ImGui::GetStyleColorName(i);
- if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
- ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23-(int)strlen(name), "", col.x, col.y, col.z, col.w);
+ if (output_dest == 0)
+ ImGui::LogToClipboard();
+ else
+ ImGui::LogToTTY();
+ ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
+ for (int i = 0; i < ImGuiCol_COUNT; i++)
+ {
+ const ImVec4& col = style.Colors[i];
+ const char* name = ImGui::GetStyleColorName(i);
+ if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
+ ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
+ }
+ ImGui::LogFinish();
}
- ImGui::LogFinish();
- }
- ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth();
- ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
+ ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth();
+ ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
- ImGui::Text("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu.");
-
- static ImGuiTextFilter filter;
- filter.Draw("Filter colors", 200);
+ static ImGuiTextFilter filter;
+ filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
- static ImGuiColorEditFlags alpha_flags = 0;
- ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine();
- ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine();
- ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
+ static ImGuiColorEditFlags alpha_flags = 0;
+ ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine();
+ ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine();
+ ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::SameLine();
+ ShowHelpMarker("In the color list:\nLeft-click on colored square to open color picker,\nRight-click to open edit options menu.");
- ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
- ImGui::PushItemWidth(-160);
- for (int i = 0; i < ImGuiCol_COUNT; i++)
- {
- const char* name = ImGui::GetStyleColorName(i);
- if (!filter.PassFilter(name))
- continue;
- ImGui::PushID(i);
- ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
- if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
+ ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
+ ImGui::PushItemWidth(-160);
+ for (int i = 0; i < ImGuiCol_COUNT; i++)
{
- // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons.
- // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient!
- ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i];
- ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i];
+ const char* name = ImGui::GetStyleColorName(i);
+ if (!filter.PassFilter(name))
+ continue;
+ ImGui::PushID(i);
+ ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
+ if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
+ {
+ // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons.
+ // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient!
+ ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i];
+ ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i];
+ }
+ ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
+ ImGui::TextUnformatted(name);
+ ImGui::PopID();
}
- ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
- ImGui::TextUnformatted(name);
- ImGui::PopID();
- }
- ImGui::PopItemWidth();
- ImGui::EndChild();
-
- ImGui::TreePop();
- }
+ ImGui::PopItemWidth();
+ ImGui::EndChild();
- bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size);
- if (fonts_opened)
- {
- ImFontAtlas* atlas = ImGui::GetIO().Fonts;
- if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
- {
- ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
- ImGui::TreePop();
+ ImGui::EndTabItem();
}
- ImGui::PushItemWidth(100);
- for (int i = 0; i < atlas->Fonts.Size; i++)
+
+ if (ImGui::BeginTabItem("Fonts"))
{
- ImFont* font = atlas->Fonts[i];
- ImGui::PushID(font);
- bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size);
- ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font;
- if (font_details_opened)
+ ImFontAtlas* atlas = ImGui::GetIO().Fonts;
+ ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading.");
+ ImGui::PushItemWidth(120);
+ for (int i = 0; i < atlas->Fonts.Size; i++)
{
- ImGui::PushFont(font);
- ImGui::Text("The quick brown fox jumps over the lazy dog");
- ImGui::PopFont();
- ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font
- ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
- ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
- ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
- ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
- ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface));
- for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
- if (ImFontConfig* cfg = &font->ConfigData[config_i])
- ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
- if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
+ ImFont* font = atlas->Fonts[i];
+ ImGui::PushID(font);
+ bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
+ ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font;
+ if (font_details_opened)
{
- // Display all glyphs of the fonts in separate pages of 256 characters
- for (int base = 0; base < 0x10000; base += 256)
+ ImGui::PushFont(font);
+ ImGui::Text("The quick brown fox jumps over the lazy dog");
+ ImGui::PopFont();
+ ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font
+ ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
+ ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
+ ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
+ ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
+ ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface));
+ for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
+ if (ImFontConfig* cfg = &font->ConfigData[config_i])
+ ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
+ if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{
- int count = 0;
- for (int n = 0; n < 256; n++)
- count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
- if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base+255, count, count > 1 ? "glyphs" : "glyph"))
+ // Display all glyphs of the fonts in separate pages of 256 characters
+ for (int base = 0; base < 0x10000; base += 256)
{
- float cell_size = font->FontSize * 1;
- float cell_spacing = style.ItemSpacing.y;
- ImVec2 base_pos = ImGui::GetCursorScreenPos();
- ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ int count = 0;
for (int n = 0; n < 256; n++)
+ count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
+ if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
{
- ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
- ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
- const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base+n));
- draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50));
- if (glyph)
- font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string.
- if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
+ float cell_size = font->FontSize * 1;
+ float cell_spacing = style.ItemSpacing.y;
+ ImVec2 base_pos = ImGui::GetCursorScreenPos();
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ for (int n = 0; n < 256; n++)
{
- ImGui::BeginTooltip();
- ImGui::Text("Codepoint: U+%04X", base+n);
- ImGui::Separator();
- ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
- ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
- ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
- ImGui::EndTooltip();
+ ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
+ ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
+ const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
+ draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
+ if (glyph)
+ font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string.
+ if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
+ {
+ ImGui::BeginTooltip();
+ ImGui::Text("Codepoint: U+%04X", base + n);
+ ImGui::Separator();
+ ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
+ ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
+ ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
+ ImGui::EndTooltip();
+ }
}
+ ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
+ ImGui::TreePop();
}
- ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
- ImGui::TreePop();
}
+ ImGui::TreePop();
}
ImGui::TreePop();
}
+ ImGui::PopID();
+ }
+ if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
+ {
+ ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
ImGui::TreePop();
}
- ImGui::PopID();
+
+ static float window_scale = 1.0f;
+ if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window
+ ImGui::SetWindowFontScale(window_scale);
+ ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything
+ ImGui::PopItemWidth();
+
+ ImGui::EndTabItem();
}
- static float window_scale = 1.0f;
- ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window
- ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything
- ImGui::PopItemWidth();
- ImGui::SetWindowFontScale(window_scale);
- ImGui::TreePop();
+
+ if (ImGui::BeginTabItem("Rendering"))
+ {
+ ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
+ ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
+ ImGui::PushItemWidth(100);
+ ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f);
+ if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
+ ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
+ ImGui::PopItemWidth();
+
+ ImGui::EndTabItem();
+ }
+
+ ImGui::EndTabBar();
}
ImGui::PopItemWidth();
@@ -3108,7 +3197,7 @@ struct ExampleAppConsole
// Portable helpers
static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; }
static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; }
- static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); }
+ static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); }
static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; }
void ClearLog()
@@ -3397,10 +3486,21 @@ struct ExampleAppLog
{
ImGuiTextBuffer Buf;
ImGuiTextFilter Filter;
- ImVector LineOffsets; // Index to lines offset
+ ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines
bool ScrollToBottom;
- void Clear() { Buf.clear(); LineOffsets.clear(); }
+ ExampleAppLog()
+ {
+ ScrollToBottom = false;
+ Clear();
+ }
+
+ void Clear()
+ {
+ Buf.clear();
+ LineOffsets.clear();
+ LineOffsets.push_back(0);
+ }
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
{
@@ -3411,13 +3511,12 @@ struct ExampleAppLog
va_end(args);
for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n')
- LineOffsets.push_back(old_size);
+ LineOffsets.push_back(old_size + 1);
ScrollToBottom = true;
}
void Draw(const char* title, bool* p_open = NULL)
{
- ImGui::SetNextWindowSize(ImVec2(500,400), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(title, p_open))
{
ImGui::End();
@@ -3430,24 +3529,47 @@ struct ExampleAppLog
Filter.Draw("Filter", -100.0f);
ImGui::Separator();
ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar);
- if (copy) ImGui::LogToClipboard();
+ if (copy)
+ ImGui::LogToClipboard();
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+ const char* buf = Buf.begin();
+ const char* buf_end = Buf.end();
if (Filter.IsActive())
{
- const char* buf_begin = Buf.begin();
- const char* line = buf_begin;
- for (int line_no = 0; line != NULL; line_no++)
+ for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
{
- const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL;
- if (Filter.PassFilter(line, line_end))
- ImGui::TextUnformatted(line, line_end);
- line = line_end && line_end[1] ? line_end + 1 : NULL;
+ const char* line_start = buf + LineOffsets[line_no];
+ const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
+ if (Filter.PassFilter(line_start, line_end))
+ ImGui::TextUnformatted(line_start, line_end);
}
}
else
{
- ImGui::TextUnformatted(Buf.begin());
+ // The simplest and easy way to display the entire buffer:
+ // ImGui::TextUnformatted(buf_begin, buf_end);
+ // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines.
+ // Here we instead demonstrate using the clipper to only process lines that are within the visible area.
+ // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended.
+ // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height,
+ // both of which we can handle since we an array pointing to the beginning of each line of text.
+ // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper.
+ // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries)
+ ImGuiListClipper clipper;
+ clipper.Begin(LineOffsets.Size);
+ while (clipper.Step())
+ {
+ for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
+ {
+ const char* line_start = buf + LineOffsets[line_no];
+ const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
+ ImGui::TextUnformatted(line_start, line_end);
+ }
+ }
+ clipper.End();
}
+ ImGui::PopStyleVar();
if (ScrollToBottom)
ImGui::SetScrollHereY(1.0f);
@@ -3462,15 +3584,23 @@ static void ShowExampleAppLog(bool* p_open)
{
static ExampleAppLog log;
- // Demo: add random items (unless Ctrl is held)
- static double last_time = -1.0;
- double time = ImGui::GetTime();
- if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl)
+ // For the demo: add a debug button before the normal log window contents
+ // We take advantage of the fact that multiple calls to Begin()/End() are appending to the same window.
+ ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
+ ImGui::Begin("Example: Log", p_open);
+ if (ImGui::SmallButton("Add 5 entries"))
{
- const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" };
- log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount());
- last_time = time;
+ static int counter = 0;
+ for (int n = 0; n < 5; n++)
+ {
+ const char* categories[3] = { "info", "warn", "error" };
+ const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
+ log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
+ ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]);
+ counter++;
+ }
}
+ ImGui::End();
log.Draw("Example: Log", p_open);
}
@@ -3483,7 +3613,7 @@ static void ShowExampleAppLog(bool* p_open)
static void ShowExampleAppLayout(bool* p_open)
{
ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
- if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar))
+ if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
{
if (ImGui::BeginMenuBar())
{
@@ -3513,7 +3643,20 @@ static void ShowExampleAppLayout(bool* p_open)
ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
ImGui::Text("MyObject: %d", selected);
ImGui::Separator();
- ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
+ if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
+ {
+ if (ImGui::BeginTabItem("Description"))
+ {
+ ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Details"))
+ {
+ ImGui::Text("ID: 0123456789");
+ ImGui::EndTabItem();
+ }
+ ImGui::EndTabBar();
+ }
ImGui::EndChild();
if (ImGui::Button("Revert")) {}
ImGui::SameLine();
@@ -3696,8 +3839,8 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500
- if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
- if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step
+ if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
+ if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
@@ -3738,6 +3881,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
// FIXME-VIEWPORT-ABS: Select a default viewport
const float DISTANCE = 10.0f;
static int corner = 0;
+ ImGuiIO& io = ImGui::GetIO();
if (corner != -1)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
@@ -3747,12 +3891,12 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
ImGui::SetNextWindowViewport(viewport->ID);
}
ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
- if (ImGui::Begin("Example: Simple Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
+ if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
{
ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
ImGui::Separator();
if (ImGui::IsMousePosValid())
- ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y);
+ ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
else
ImGui::Text("Mouse Position: ");
if (ImGui::BeginPopupContextWindow())
@@ -3827,27 +3971,30 @@ static void ShowExampleAppCustomRendering(bool* p_open)
static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
- ImGui::ColorEdit3("Color", &col.x);
+ ImGui::ColorEdit4("Color", &col.x);
{
const ImVec2 p = ImGui::GetCursorScreenPos();
const ImU32 col32 = ImColor(col);
float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f;
for (int n = 0; n < 2; n++)
{
- float curr_thickness = (n == 0) ? 1.0f : thickness;
- draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, curr_thickness); x += sz+spacing;
- draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, curr_thickness); x += sz+spacing;
- draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, curr_thickness); x += sz+spacing;
- draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, curr_thickness); x += sz+spacing;
- draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, curr_thickness); x += sz+spacing;
- draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, curr_thickness); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
- draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, curr_thickness); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
- draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, curr_thickness); x += sz+spacing; // Diagonal line
- draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, curr_thickness);
+ // First line uses a thickness of 1.0, second line uses the configurable thickness
+ float th = (n == 0) ? 1.0f : thickness;
+ draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6, th); x += sz+spacing; // Hexagon
+ draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, th); x += sz+spacing; // Circle
+ draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, th); x += sz+spacing;
+ draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, th); x += sz+spacing;
+ draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, th); x += sz+spacing;
+ draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, th); x += sz+spacing;
+ draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, th); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
+ draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
+ draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, th); x += sz+spacing; // Diagonal line
+ draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, th);
x = p.x + 4;
y += sz+spacing;
}
- draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing;
+ draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6); x += sz+spacing; // Hexagon
+ draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; // Circle
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing;
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing;
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight); x += sz+spacing;
@@ -3974,6 +4121,7 @@ void ShowExampleAppDockSpace(bool* p_open)
if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (opt_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) opt_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode;
if (ImGui::MenuItem("Flag: NoResize", "", (opt_flags & ImGuiDockNodeFlags_NoResize) != 0)) opt_flags ^= ImGuiDockNodeFlags_NoResize;
if (ImGui::MenuItem("Flag: PassthruDockspace", "", (opt_flags & ImGuiDockNodeFlags_PassthruDockspace) != 0)) opt_flags ^= ImGuiDockNodeFlags_PassthruDockspace;
+ if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (opt_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) opt_flags ^= ImGuiDockNodeFlags_AutoHideTabBar;
ImGui::Separator();
if (ImGui::MenuItem("Close DockSpace", NULL, false, p_open != NULL))
*p_open = false;
@@ -4004,16 +4152,16 @@ struct MyDocument
bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo)
bool OpenPrev; // Copy of Open from last update.
bool Dirty; // Set when the document has been modified
- bool WantClose; // Set when the document
+ bool WantClose; // Set when the document
ImVec4 Color; // An arbitrary variable associated to the document
MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f))
- {
- Name = name;
- Open = OpenPrev = open;
- Dirty = false;
- WantClose = false;
- Color = color;
+ {
+ Name = name;
+ Open = OpenPrev = open;
+ Dirty = false;
+ WantClose = false;
+ Color = color;
}
void DoOpen() { Open = true; }
void DoQueueClose() { WantClose = true; }
@@ -4068,10 +4216,10 @@ struct ExampleAppDocuments
}
};
-// [Optional] Notify the system of Tabs/Windows of closure that happened outside the regular tab interface
+// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed
-// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence.
-// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar
+// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence.
+// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar
// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame.
// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
@@ -4090,20 +4238,32 @@ void ShowExampleAppDocuments(bool* p_open)
{
static ExampleAppDocuments app;
- ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar);
-
// Options
enum Target
{
Target_None,
- Target_Tab, // Create document as a local tab into a local tab bar
- Target_Window // Create document as a regular window
+ Target_Tab, // Create documents as local tab into a local tab bar
+ Target_DockspaceAndWindow // Create documents as regular windows, and create an embedded dockspace
};
static Target opt_target = Target_Tab;
static bool opt_reorderable = true;
static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
- // Menu
+ // When (opt_target == Target_DockspaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
+ // that we emit gets docked into the same spot as the parent window ("Example: Documents").
+ // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
+ // not visible, which in turn would stop submitting the "Eggplant" window.
+ // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
+ // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
+
+ bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
+ if (!window_contents_visible && opt_target != Target_DockspaceAndWindow)
+ {
+ ImGui::End();
+ return;
+ }
+
+ // Menu Bar
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("File"))
@@ -4148,8 +4308,8 @@ void ShowExampleAppDocuments(bool* p_open)
ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
ImGui::PopItemWidth();
bool redock_all = false;
- if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
- if (opt_target == Target_Window) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
+ if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
+ if (opt_target == Target_DockspaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
ImGui::Separator();
@@ -4194,7 +4354,7 @@ void ShowExampleAppDocuments(bool* p_open)
ImGui::EndTabBar();
}
}
- else if (opt_target == Target_Window)
+ else if (opt_target == Target_DockspaceAndWindow)
{
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
@@ -4214,7 +4374,7 @@ void ShowExampleAppDocuments(bool* p_open)
// FIXME-DOCK: SetNextWindowDock()
//ImGuiID default_dock_id = GetDockspaceRootDocumentDockID();
//ImGuiID default_dock_id = GetDockspacePreferedDocumentDockID();
- ImGui::SetNextWindowDockId(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
@@ -4238,6 +4398,13 @@ void ShowExampleAppDocuments(bool* p_open)
}
}
+ // Early out other contents
+ if (!window_contents_visible)
+ {
+ ImGui::End();
+ return;
+ }
+
// Update closing queue
static ImVector close_queue;
if (close_queue.empty())
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index b873b3f8..bcafa0b3 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.67 WIP
+// dear imgui, v1.68 WIP
// (drawing and font code)
/*
@@ -12,7 +12,8 @@ Index of this file:
// [SECTION] Helpers ShadeVertsXXX functions
// [SECTION] ImFontConfig
// [SECTION] ImFontAtlas
-// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder
+// [SECTION] ImFontAtlas glyph ranges helpers
+// [SECTION] ImFontGlyphRangesBuilder
// [SECTION] ImFont
// [SECTION] Internal Render Helpers
// [SECTION] Decompression code
@@ -56,6 +57,9 @@ Index of this file:
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
+#endif
#if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
#endif
@@ -63,7 +67,7 @@ Index of this file:
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
#endif
#if __has_warning("-Wdouble-promotion")
-#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
+#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#endif
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
@@ -175,7 +179,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
- colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f);
+ colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
@@ -206,10 +210,10 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
+ colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
- colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
@@ -263,10 +267,10 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
+ colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
- colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
@@ -321,10 +325,10 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
+ colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
- colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
@@ -661,7 +665,13 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
_IdxWritePtr += 6;
}
+// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds.
+// Those macros expects l-values.
+#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } }
+#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } }
+
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
+// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
{
if (points_count < 2)
@@ -685,16 +695,17 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
PrimReserve(idx_count, vtx_count);
// Temporary buffer
- ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
+ ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630
ImVec2* temp_points = temp_normals + points_count;
for (int i1 = 0; i1 < count; i1++)
{
const int i2 = (i1+1) == points_count ? 0 : i1+1;
- ImVec2 diff = points[i2] - points[i1];
- diff *= ImInvLength(diff, 1.0f);
- temp_normals[i1].x = diff.y;
- temp_normals[i1].y = -diff.x;
+ float dx = points[i2].x - points[i1].x;
+ float dy = points[i2].y - points[i1].y;
+ IM_NORMALIZE2F_OVER_ZERO(dx, dy);
+ temp_normals[i1].x = dy;
+ temp_normals[i1].y = -dx;
}
if (!closed)
temp_normals[points_count-1] = temp_normals[points_count-2];
@@ -717,17 +728,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
// Average normals
- ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
- if (dmr2 > 0.000001f)
- {
- float scale = 1.0f / dmr2;
- if (scale > 100.0f) scale = 100.0f;
- dm *= scale;
- }
- dm *= AA_SIZE;
- temp_points[i2*2+0] = points[i2] + dm;
- temp_points[i2*2+1] = points[i2] - dm;
+ float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
+ float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
+ IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f)
+ dm_x *= AA_SIZE;
+ dm_y *= AA_SIZE;
+
+ // Add temporary vertexes
+ ImVec2* out_vtx = &temp_points[i2*2];
+ out_vtx[0].x = points[i2].x + dm_x;
+ out_vtx[0].y = points[i2].y + dm_y;
+ out_vtx[1].x = points[i2].x - dm_x;
+ out_vtx[1].y = points[i2].y - dm_y;
// Add indexes
_IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
@@ -771,20 +783,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
// Average normals
- ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
- if (dmr2 > 0.000001f)
- {
- float scale = 1.0f / dmr2;
- if (scale > 100.0f) scale = 100.0f;
- dm *= scale;
- }
- ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
- ImVec2 dm_in = dm * half_inner_thickness;
- temp_points[i2*4+0] = points[i2] + dm_out;
- temp_points[i2*4+1] = points[i2] + dm_in;
- temp_points[i2*4+2] = points[i2] - dm_in;
- temp_points[i2*4+3] = points[i2] - dm_out;
+ float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
+ float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
+ IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
+ float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
+ float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
+ float dm_in_x = dm_x * half_inner_thickness;
+ float dm_in_y = dm_y * half_inner_thickness;
+
+ // Add temporary vertexes
+ ImVec2* out_vtx = &temp_points[i2*4];
+ out_vtx[0].x = points[i2].x + dm_out_x;
+ out_vtx[0].y = points[i2].y + dm_out_y;
+ out_vtx[1].x = points[i2].x + dm_in_x;
+ out_vtx[1].y = points[i2].y + dm_in_y;
+ out_vtx[2].x = points[i2].x - dm_in_x;
+ out_vtx[2].y = points[i2].y - dm_in_y;
+ out_vtx[3].x = points[i2].x - dm_out_x;
+ out_vtx[3].y = points[i2].y - dm_out_y;
// Add indexes
_IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
@@ -822,11 +838,13 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
const int i2 = (i1+1) == points_count ? 0 : i1+1;
const ImVec2& p1 = points[i1];
const ImVec2& p2 = points[i2];
- ImVec2 diff = p2 - p1;
- diff *= ImInvLength(diff, 1.0f);
- const float dx = diff.x * (thickness * 0.5f);
- const float dy = diff.y * (thickness * 0.5f);
+ float dx = p2.x - p1.x;
+ float dy = p2.y - p1.y;
+ IM_NORMALIZE2F_OVER_ZERO(dx, dy);
+ dx *= (thickness * 0.5f);
+ dy *= (thickness * 0.5f);
+
_VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
_VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
_VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
@@ -841,6 +859,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
}
}
+// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
{
if (points_count < 3)
@@ -867,15 +886,16 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
}
// Compute normals
- ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
+ ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
{
const ImVec2& p0 = points[i0];
const ImVec2& p1 = points[i1];
- ImVec2 diff = p1 - p0;
- diff *= ImInvLength(diff, 1.0f);
- temp_normals[i0].x = diff.y;
- temp_normals[i0].y = -diff.x;
+ float dx = p1.x - p0.x;
+ float dy = p1.y - p0.y;
+ IM_NORMALIZE2F_OVER_ZERO(dx, dy);
+ temp_normals[i0].x = dy;
+ temp_normals[i0].y = -dx;
}
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
@@ -883,19 +903,15 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
// Average normals
const ImVec2& n0 = temp_normals[i0];
const ImVec2& n1 = temp_normals[i1];
- ImVec2 dm = (n0 + n1) * 0.5f;
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
- if (dmr2 > 0.000001f)
- {
- float scale = 1.0f / dmr2;
- if (scale > 100.0f) scale = 100.0f;
- dm *= scale;
- }
- dm *= AA_SIZE * 0.5f;
+ float dm_x = (n0.x + n1.x) * 0.5f;
+ float dm_y = (n0.y + n1.y) * 0.5f;
+ IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
+ dm_x *= AA_SIZE * 0.5f;
+ dm_y *= AA_SIZE * 0.5f;
// Add vertices
- _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
- _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
+ _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
+ _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
_VtxWritePtr += 2;
// Add indexes for fringes
@@ -947,6 +963,9 @@ void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, floa
_Path.push_back(centre);
return;
}
+
+ // Note that we are adding a point at both a_min and a_max.
+ // If you are trying to draw a full closed circle you don't want the overlapping points!
_Path.reserve(_Path.Size + (num_segments + 1));
for (int i = 0; i <= num_segments; i++)
{
@@ -1130,21 +1149,23 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
{
- if ((col & IM_COL32_A_MASK) == 0)
+ if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
return;
+ // Because we are filling a closed shape we remove 1 from the count of segments/points
const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
- PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments);
+ PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1);
PathStroke(col, true, thickness);
}
void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
{
- if ((col & IM_COL32_A_MASK) == 0)
+ if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
return;
+ // Because we are filling a closed shape we remove 1 from the count of segments/points
const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
- PathArcTo(centre, radius, 0.0f, a_max, num_segments);
+ PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1);
PathFillConvex(col);
}
@@ -1510,7 +1531,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid
GetTexDataAsAlpha8(&pixels, NULL, NULL);
if (pixels)
{
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
+ TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
const unsigned char* src = pixels;
unsigned int* dst = TexPixelsRGBA32;
for (int n = TexWidth * TexHeight; n > 0; n--)
@@ -1534,11 +1555,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
if (!font_cfg->MergeMode)
Fonts.push_back(IM_NEW(ImFont));
else
- IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
+ IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
ConfigData.push_back(*font_cfg);
ImFontConfig& new_font_cfg = ConfigData.back();
- if (!new_font_cfg.DstFont)
+ if (new_font_cfg.DstFont == NULL)
new_font_cfg.DstFont = Fonts.back();
if (!new_font_cfg.FontDataOwnedByAtlas)
{
@@ -1726,139 +1747,220 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
data[i] = table[data[i]];
}
+// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
+// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
+struct ImFontBuildSrcData
+{
+ stbtt_fontinfo FontInfo;
+ stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
+ stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
+ stbtt_packedchar* PackedChars; // Output glyphs
+ const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
+ int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
+ int GlyphsHighest; // Highest requested codepoint
+ int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
+ ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
+ ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap)
+};
+
+// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
+struct ImFontBuildDstData
+{
+ int SrcCount; // Number of source fonts targeting this destination font.
+ int GlyphsHighest;
+ int GlyphsCount;
+ ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
+};
+
+static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector* out)
+{
+ IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
+ const int* it_begin = in->Storage.begin();
+ const int* it_end = in->Storage.end();
+ for (const int* it = it_begin; it < it_end; it++)
+ if (int entries_32 = *it)
+ for (int bit_n = 0; bit_n < 32; bit_n++)
+ if (entries_32 & (1 << bit_n))
+ out->push_back((int)((it - it_begin) << 5) + bit_n);
+}
+
bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
{
IM_ASSERT(atlas->ConfigData.Size > 0);
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
+ // Clear atlas
atlas->TexID = (ImTextureID)NULL;
atlas->TexWidth = atlas->TexHeight = 0;
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
atlas->ClearTexData();
- // Count glyphs/ranges
- int total_glyphs_count = 0;
- int total_ranges_count = 0;
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
- {
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- if (!cfg.GlyphRanges)
- cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
- for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
- total_glyphs_count += (in_range[1] - in_range[0]) + 1;
- }
-
- // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
- // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
- atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
- atlas->TexHeight = 0;
-
- // Start packing
- const int max_tex_height = 1024*32;
- stbtt_pack_context spc = {};
- if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL))
- return false;
- stbtt_PackSetOversampling(&spc, 1, 1);
+ // Temporary storage for building
+ ImVector src_tmp_array;
+ ImVector dst_tmp_array;
+ src_tmp_array.resize(atlas->ConfigData.Size);
+ dst_tmp_array.resize(atlas->Fonts.Size);
+ memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
+ memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
- // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
- ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
-
- // Initialize font information (so we can error without any cleanup)
- struct ImFontTempBuildData
+ // 1. Initialize font loading structure, check font data validity
+ for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
{
- stbtt_fontinfo FontInfo;
- stbrp_rect* Rects;
- int RectsCount;
- stbtt_pack_range* Ranges;
- int RangesCount;
- };
- ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
- {
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- ImFontTempBuildData& tmp = tmp_array[input_i];
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
+ // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
+ src_tmp.DstIndex = -1;
+ for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
+ if (cfg.DstFont == atlas->Fonts[output_i])
+ src_tmp.DstIndex = output_i;
+ IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
+ if (src_tmp.DstIndex == -1)
+ return false;
+
+ // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
- if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
- {
- atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure
- ImGui::MemFree(tmp_array);
+ if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
return false;
- }
+
+ // Measure highest codepoints
+ ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
+ src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
+ for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
+ src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
+ dst_tmp.SrcCount++;
+ dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
+ }
+
+ // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
+ int total_glyphs_count = 0;
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
+ if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
+ dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
+
+ for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
+ for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
+ {
+ if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
+ continue;
+ if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font?
+ continue;
+
+ // Add to avail set/counters
+ src_tmp.GlyphsCount++;
+ dst_tmp.GlyphsCount++;
+ src_tmp.GlyphsSet.SetBit(codepoint, true);
+ if (dst_tmp.SrcCount > 1)
+ dst_tmp.GlyphsSet.SetBit(codepoint, true);
+ total_glyphs_count++;
+ }
+ }
+
+ // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
+ UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
+ src_tmp.GlyphsSet.Clear();
+ IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
}
+ for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
+ dst_tmp_array[dst_i].GlyphsSet.Clear();
+ dst_tmp_array.clear();
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
- int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
- stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
- stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
- stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
- memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
- memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
- memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
-
- // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
- {
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- ImFontTempBuildData& tmp = tmp_array[input_i];
-
- // Setup ranges
- int font_glyphs_count = 0;
- int font_ranges_count = 0;
- for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
- font_glyphs_count += (in_range[1] - in_range[0]) + 1;
- tmp.Ranges = buf_ranges + buf_ranges_n;
- tmp.RangesCount = font_ranges_count;
- buf_ranges_n += font_ranges_count;
- for (int i = 0; i < font_ranges_count; i++)
- {
- const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
- stbtt_pack_range& range = tmp.Ranges[i];
- range.font_size = cfg.SizePixels;
- range.first_unicode_codepoint_in_range = in_range[0];
- range.num_chars = (in_range[1] - in_range[0]) + 1;
- range.chardata_for_range = buf_packedchars + buf_packedchars_n;
- buf_packedchars_n += range.num_chars;
- }
+ // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
+ ImVector buf_rects;
+ ImVector buf_packedchars;
+ buf_rects.resize(total_glyphs_count);
+ buf_packedchars.resize(total_glyphs_count);
+ memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
+ memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
+
+ // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
+ int total_surface = 0;
+ int buf_rects_out_n = 0;
+ int buf_packedchars_out_n = 0;
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
- // Gather the sizes of all rectangle we need
- tmp.Rects = buf_rects + buf_rects_n;
- tmp.RectsCount = font_glyphs_count;
- buf_rects_n += font_glyphs_count;
- stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
- int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
- IM_ASSERT(n == font_glyphs_count);
-
- // Detect missing glyphs and replace them with a zero-sized box instead of relying on the default glyphs
- // This allows us merging overlapping icon fonts more easily.
- int rect_i = 0;
- for (int range_i = 0; range_i < tmp.RangesCount; range_i++)
- for (int char_i = 0; char_i < tmp.Ranges[range_i].num_chars; char_i++, rect_i++)
- if (stbtt_FindGlyphIndex(&tmp.FontInfo, tmp.Ranges[range_i].first_unicode_codepoint_in_range + char_i) == 0)
- tmp.Rects[rect_i].w = tmp.Rects[rect_i].h = 0;
-
- // Pack
- stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
-
- // Extend texture height
- // Also mark missing glyphs as non-packed so we don't attempt to render into them
- for (int i = 0; i < n; i++)
+ src_tmp.Rects = &buf_rects[buf_rects_out_n];
+ src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
+ buf_rects_out_n += src_tmp.GlyphsCount;
+ buf_packedchars_out_n += src_tmp.GlyphsCount;
+
+ // Convert our ranges in the format stb_truetype wants
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ src_tmp.PackRange.font_size = cfg.SizePixels;
+ src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
+ src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
+ src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
+ src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
+ src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
+ src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
+
+ // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
+ const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
+ const int padding = atlas->TexGlyphPadding;
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
{
- if (tmp.Rects[i].w == 0 && tmp.Rects[i].h == 0)
- tmp.Rects[i].was_packed = 0;
- if (tmp.Rects[i].was_packed)
- atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
+ int x0, y0, x1, y1;
+ const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
+ IM_ASSERT(glyph_index_in_font != 0);
+ stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
+ src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
+ src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
+ total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
}
}
- IM_ASSERT(buf_rects_n == total_glyphs_count);
- IM_ASSERT(buf_packedchars_n == total_glyphs_count);
- IM_ASSERT(buf_ranges_n == total_ranges_count);
- // Create texture
+ // We need a width for the skyline algorithm, any width!
+ // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
+ // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
+ const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
+ atlas->TexHeight = 0;
+ if (atlas->TexDesiredWidth > 0)
+ atlas->TexWidth = atlas->TexDesiredWidth;
+ else
+ atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
+
+ // 5. Start packing
+ // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
+ const int TEX_HEIGHT_MAX = 1024 * 32;
+ stbtt_pack_context spc = {};
+ stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
+ ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
+
+ // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
+
+ stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
+
+ // Extend texture height and mark missing glyphs as non-packed so we won't render them.
+ // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
+ if (src_tmp.Rects[glyph_i].was_packed)
+ atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
+ }
+
+ // 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
@@ -1866,41 +1968,46 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
spc.pixels = atlas->TexPixelsAlpha8;
spc.height = atlas->TexHeight;
- // Second pass: render font characters
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
+ // 8. Render/rasterize font characters into the texture
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- ImFontTempBuildData& tmp = tmp_array[input_i];
- stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
- stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
+
+ stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
+
+ // Apply multiply operator
if (cfg.RasterizerMultiply != 1.0f)
{
unsigned char multiply_table[256];
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
- for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
+ stbrp_rect* r = &src_tmp.Rects[0];
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
if (r->was_packed)
- ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
+ ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
}
- tmp.Rects = NULL;
+ src_tmp.Rects = NULL;
}
// End packing
stbtt_PackEnd(&spc);
- ImGui::MemFree(buf_rects);
- buf_rects = NULL;
+ buf_rects.clear();
- // Third pass: setup ImFont and glyphs for runtime
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
+ // 9. Setup ImFont and glyphs for runtime
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- ImFontTempBuildData& tmp = tmp_array[input_i];
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
+
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
- if (cfg.MergeMode)
- dst_font->BuildLookupTable();
- const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
+ const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
- stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
+ stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
@@ -1908,40 +2015,30 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
const float font_off_x = cfg.GlyphOffset.x;
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
- for (int i = 0; i < tmp.RangesCount; i++)
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
{
- stbtt_pack_range& range = tmp.Ranges[i];
- for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
- {
- const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
- if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
- continue;
-
- const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
- if (cfg.MergeMode && dst_font->FindGlyphNoFallback((ImWchar)codepoint))
- continue;
-
- float char_advance_x_org = pc.xadvance;
- float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
- float char_off_x = font_off_x;
- if (char_advance_x_org != char_advance_x_mod)
- char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
-
- stbtt_aligned_quad q;
- float dummy_x = 0.0f, dummy_y = 0.0f;
- stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
- dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
- }
+ const int codepoint = src_tmp.GlyphsList[glyph_i];
+ const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
+
+ const float char_advance_x_org = pc.xadvance;
+ const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
+ float char_off_x = font_off_x;
+ if (char_advance_x_org != char_advance_x_mod)
+ char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
+
+ // Register glyph
+ stbtt_aligned_quad q;
+ float dummy_x = 0.0f, dummy_y = 0.0f;
+ stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0);
+ dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
}
}
- // Cleanup temporaries
- ImGui::MemFree(buf_packedchars);
- ImGui::MemFree(buf_ranges);
- ImGui::MemFree(tmp_array);
+ // Cleanup temporary (ImVector doesn't honor destructor)
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ src_tmp_array[src_i].~ImFontBuildSrcData();
ImFontAtlasBuildFinish(atlas);
-
return true;
}
@@ -1969,16 +2066,17 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
font->ConfigDataCount++;
}
-void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
+void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
{
- stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
+ stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
+ IM_ASSERT(pack_context != NULL);
ImVector& user_rects = atlas->CustomRects;
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
ImVector pack_rects;
pack_rects.resize(user_rects.Size);
- memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
+ memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
for (int i = 0; i < user_rects.Size; i++)
{
pack_rects[i].w = user_rects[i].Width;
@@ -2078,7 +2176,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()
static const ImWchar ranges[] =
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
- 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
+ 0x2000, 0x206F, // General Punctuation
+ 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions
0xFF00, 0xFFEF, // Half-width characters
0x4e00, 0x9FAF, // CJK Ideograms
@@ -2098,7 +2197,7 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short*
}
//-------------------------------------------------------------------------
-// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder
+// [SECTION] ImFontAtlas glyph ranges helpers
//-------------------------------------------------------------------------
const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
@@ -2106,7 +2205,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
// Store 2500 regularly used characters for Simplified Chinese.
// Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8
// This table covers 97.97% of all characters used during the month in July, 1987.
- // You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
+ // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
static const short accumulative_offsets_from_0x4E00[] =
{
@@ -2154,9 +2253,10 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
static ImWchar base_ranges[] = // not zero-terminated
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
- 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
+ 0x2000, 0x206F, // General Punctuation
+ 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions
- 0xFF00, 0xFFEF, // Half-width characters
+ 0xFF00, 0xFFEF // Half-width characters
};
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
if (!full_ranges[0])
@@ -2172,7 +2272,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
// 1946 common ideograms code points for Japanese
// Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering
// FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this.
- // You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
+ // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
static const short accumulative_offsets_from_0x4E00[] =
{
@@ -2207,14 +2307,14 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16,
4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2,
1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65,
- 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
+ 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
};
static ImWchar base_ranges[] = // not zero-terminated
{
0x0020, 0x00FF, // Basic Latin + Latin Supplement
- 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
+ 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
0x31F0, 0x31FF, // Katakana Phonetic Extensions
- 0xFF00, 0xFFEF, // Half-width characters
+ 0xFF00, 0xFFEF // Half-width characters
};
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
if (!full_ranges[0])
@@ -2250,7 +2350,11 @@ const ImWchar* ImFontAtlas::GetGlyphRangesThai()
return &ranges[0];
}
-void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
+//-----------------------------------------------------------------------------
+// [SECTION] ImFontGlyphRangesBuilder
+//-----------------------------------------------------------------------------
+
+void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
{
while (text_end ? (text < text_end) : *text)
{
@@ -2264,14 +2368,14 @@ void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text
}
}
-void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
+void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
{
for (; ranges[0]; ranges += 2)
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
AddChar(c);
}
-void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector* out_ranges)
+void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges)
{
for (int n = 0; n < 0x10000; n++)
if (GetBit(n))
@@ -2423,7 +2527,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
{
if (c >= IndexLookup.Size)
return FallbackGlyph;
- const ImWchar i = IndexLookup[c];
+ const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1)
return FallbackGlyph;
return &Glyphs.Data[i];
@@ -2433,7 +2537,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
{
if (c >= IndexLookup.Size)
return NULL;
- const ImWchar i = IndexLookup[c];
+ const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1)
return NULL;
return &Glyphs.Data[i];
@@ -2493,7 +2597,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
}
}
- const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
+ const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
if (ImCharIsBlankW(c))
{
if (inside_word)
@@ -2610,7 +2714,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
continue;
}
- const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
+ const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
if (line_width + char_width >= max_width)
{
s = prev_s;
@@ -2932,13 +3036,14 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
const float inv_rounding = 1.0f / rounding;
const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
+ const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
const float x0 = ImMax(p0.x, rect.Min.x + rounding);
if (arc0_b == arc0_e)
{
draw_list->PathLineTo(ImVec2(x0, p1.y));
draw_list->PathLineTo(ImVec2(x0, p0.y));
}
- else if (arc0_b == 0.0f && arc0_e == IM_PI*0.5f)
+ else if (arc0_b == 0.0f && arc0_e == half_pi)
{
draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
@@ -2958,7 +3063,7 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
draw_list->PathLineTo(ImVec2(x1, p0.y));
draw_list->PathLineTo(ImVec2(x1, p1.y));
}
- else if (arc1_b == 0.0f && arc1_e == IM_PI*0.5f)
+ else if (arc1_b == 0.0f && arc1_e == half_pi)
{
draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR
@@ -2990,10 +3095,12 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect
if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight);
}
-// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem... can't rely on font glyph having it, and regular dot are typically too wide.
-// If we render a dot/shape ourselves it comes with the risk that it wouldn't match the boldness or positioning of what the font uses...
-void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col)
+// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
+// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
+// the boldness or positioning of what the font uses...
+void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col)
{
+ ImFont* font = draw_list->_Data->Font;
pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f);
for (int dot_n = 0; dot_n < count; dot_n++)
draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col);
diff --git a/imgui_internal.h b/imgui_internal.h
index 932f139a..2f6600af 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.67 WIP
+// dear imgui, v1.68 WIP
// (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@@ -6,8 +6,27 @@
// #define IMGUI_DEFINE_MATH_OPERATORS
// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
+/*
+
+Index of this file:
+// Header mess
+// Forward declarations
+// STB libraries includes
+// Context pointer
+// Generic helpers
+// Misc data structures
+// Main imgui context
+// Tab bar, tab item
+// Internal API
+
+*/
+
#pragma once
+//-----------------------------------------------------------------------------
+// Header mess
+//-----------------------------------------------------------------------------
+
#ifndef IMGUI_VERSION
#error Must include imgui.h before imgui_internal.h
#endif
@@ -24,13 +43,19 @@
#ifdef __clang__
#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
-#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
+#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
+#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
#pragma clang diagnostic ignored "-Wold-style-cast"
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+#if __has_warning("-Wdouble-promotion")
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#endif
#endif
//-----------------------------------------------------------------------------
-// Forward Declarations
+// Forward declarations
//-----------------------------------------------------------------------------
struct ImRect; // An axis-aligned rectangle (2 points)
@@ -71,7 +96,7 @@ typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags:
typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior()
//-------------------------------------------------------------------------
-// STB libraries
+// STB libraries includes
//-------------------------------------------------------------------------
namespace ImGuiStb
@@ -87,7 +112,7 @@ namespace ImGuiStb
} // namespace ImGuiStb
//-----------------------------------------------------------------------------
-// Context
+// Context pointer
//-----------------------------------------------------------------------------
#ifndef GImGui
@@ -98,7 +123,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
#define IMGUI_PAYLOAD_TYPE_WINDOW "_IMWINDOW" // Payload == ImGuiWindow*
//-----------------------------------------------------------------------------
-// Helpers
+// Generic helpers
//-----------------------------------------------------------------------------
#define IM_PI 3.14159265358979323846f
@@ -108,7 +133,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
#define IM_NEWLINE "\n"
#endif
-#define IMGUI_DEBUG_LOG(FMT,...) printf("[%05d] " FMT, GImGui->FrameCount, __VA_ARGS__)
+#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
@@ -129,7 +154,8 @@ IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
// Helpers: Misc
-IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings
+IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0);
+IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed = 0);
IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0);
IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode);
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
@@ -137,6 +163,9 @@ static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c =
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
#define ImQsort qsort
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68]
+#endif
// Helpers: Geometry
IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
@@ -150,6 +179,7 @@ IMGUI_API int ImStricmp(const char* str1, const char* str2);
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count);
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count);
IMGUI_API char* ImStrdup(const char* str);
+IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str);
IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c);
IMGUI_API int ImStrlenW(const ImWchar* str);
IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line
@@ -161,7 +191,7 @@ IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* f
IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
IMGUI_API const char* ImParseFormatFindStart(const char* format);
IMGUI_API const char* ImParseFormatFindEnd(const char* format);
-IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, int buf_size);
+IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size);
IMGUI_API int ImParseFormatPrecision(const char* format, int default_value);
// Helpers: ImVec2/ImVec4 operators
@@ -224,6 +254,18 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a)
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
+// Helper: ImBoolVector. Store 1-bit per value.
+// Note that Resize() currently clears the whole vector.
+struct ImBoolVector
+{
+ ImVector Storage;
+ ImBoolVector() { }
+ void Resize(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
+ void Clear() { Storage.clear(); }
+ bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (Storage[off] & mask) != 0; }
+ void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; }
+};
+
// Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer,
// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object.
typedef int ImPoolIdx;
@@ -249,7 +291,7 @@ struct IMGUI_API ImPool
};
//-----------------------------------------------------------------------------
-// Types
+// Misc data structures
//-----------------------------------------------------------------------------
enum ImGuiButtonFlags_
@@ -330,15 +372,25 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HoveredRect = 1 << 0,
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1,
ImGuiItemStatusFlags_Edited = 1 << 2 // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
+
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ , // [imgui-test only]
+ ImGuiItemStatusFlags_Openable = 1 << 10, //
+ ImGuiItemStatusFlags_Opened = 1 << 11, //
+ ImGuiItemStatusFlags_Checkable = 1 << 12, //
+ ImGuiItemStatusFlags_Checked = 1 << 13 //
+#endif
};
// FIXME: this is in development, not exposed/functional as a generic feature yet.
+// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2
enum ImGuiLayoutType_
{
- ImGuiLayoutType_Vertical,
- ImGuiLayoutType_Horizontal
+ ImGuiLayoutType_Horizontal = 0,
+ ImGuiLayoutType_Vertical = 1
};
+// X/Y enums are fixed to 0/1 so they may be used to index ImVec2
enum ImGuiAxis
{
ImGuiAxis_None = -1,
@@ -408,13 +460,20 @@ enum ImGuiNavForward
ImGuiNavForward_ForwardActive
};
+enum ImGuiNavLayer
+{
+ ImGuiNavLayer_Main = 0, // Main scrolling layer
+ ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu)
+ ImGuiNavLayer_COUNT
+};
+
enum ImGuiPopupPositionPolicy
{
ImGuiPopupPositionPolicy_Default,
ImGuiPopupPositionPolicy_ComboBox
};
-// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches)
+// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
struct ImVec1
{
float x;
@@ -551,17 +610,17 @@ struct ImGuiWindowSettings
ImVec2 ViewportPos;
ImGuiID ViewportId;
ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none.
- ImGuiID DockFamilyId; // ID of dock family if specified
+ ImGuiID ClassId; // ID of window class if specified
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
bool Collapsed;
- ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ViewportPos = ImVec2(0, 0); ViewportId = DockId = DockFamilyId = 0; DockOrder = -1; Collapsed = false; }
+ ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ViewportPos = ImVec2(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = false; }
};
struct ImGuiSettingsHandler
{
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
- ImGuiID TypeHash; // == ImHash(TypeName, 0, 0)
+ ImGuiID TypeHash; // == ImHashStr(TypeName, 0, 0)
void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf'
@@ -654,6 +713,7 @@ enum ImGuiViewportFlagsPrivate_
};
// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!)
+// Note that every instance of ImGuiViewport is in fact a ImGuiViewportP.
struct ImGuiViewportP : public ImGuiViewport
{
int Idx;
@@ -666,8 +726,8 @@ struct ImGuiViewportP : public ImGuiViewport
float LastAlpha;
short PlatformMonitor;
bool PlatformWindowCreated;
- bool PlatformWindowMinimized;
- ImGuiWindow* Window; // Set when the viewport is owned by a window
+ bool PlatformWindowMinimized; // When minimized we tend to avoid using the viewport pos/size for clipping window or testing if they are contained in the viewport
+ ImGuiWindow* Window; // Set when the viewport is owned by a window (and ImGuiViewportFlags_CanHostOtherWindows is NOT set)
ImDrawList* OverlayDrawList; // For convenience, a draw list we can render to that's always rendered last (we use it to draw software mouse cursor when io.MouseDrawCursor is set)
ImDrawData DrawDataP;
ImDrawDataBuilder DrawDataBuilder;
@@ -675,10 +735,11 @@ struct ImGuiViewportP : public ImGuiViewport
ImVec2 LastPlatformSize;
ImVec2 LastRendererSize;
- ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = PlatformWindowMinimized = false; Window = NULL; OverlayDrawList = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); }
- ~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); }
- ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
- ImVec2 GetCenter() const{ return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); }
+ ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameOverlayDrawList = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = PlatformWindowMinimized = false; Window = NULL; OverlayDrawList = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); }
+ ~ImGuiViewportP() { if (OverlayDrawList) IM_DELETE(OverlayDrawList); }
+ ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
+ ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); }
+ void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
};
struct ImGuiNavMoveResult
@@ -718,7 +779,7 @@ struct ImGuiNextWindowData
float BgAlphaVal;
ImGuiID ViewportId;
ImGuiID DockId;
- ImGuiDockFamily DockFamily;
+ ImGuiWindowClass WindowClass;
ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it.
ImGuiNextWindowData()
@@ -738,7 +799,7 @@ struct ImGuiNextWindowData
void Clear()
{
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0;
- DockFamily = ImGuiDockFamily();
+ WindowClass = ImGuiWindowClass();
}
};
@@ -752,6 +813,18 @@ struct ImGuiTabBarSortItem
float Width;
};
+enum ImGuiDockNodeFlagsPrivate_
+{
+ ImGuiDockNodeFlags_Dockspace = 1 << 10
+};
+
+enum ImGuiDataAutority
+{
+ ImGuiDataAutority_Auto,
+ ImGuiDataAutority_DockNode,
+ ImGuiDataAutority_Window
+};
+
// sizeof() 116~160
struct ImGuiDockNode
{
@@ -765,23 +838,23 @@ struct ImGuiDockNode
ImVec2 Size; // Current size
ImVec2 SizeRef; // [Split node only] Last explicitly written-to size (overridden when using a splitter affecting the node), used to calculate Size.
int SplitAxis; // [Split node only] Split axis (X or Y)
- ImGuiDockFamily DockFamily;
+ ImGuiWindowClass WindowClass;
ImGuiWindow* HostWindow;
- ImGuiWindow* VisibleWindow;
+ ImGuiWindow* VisibleWindow; // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window.
ImGuiDockNode* CentralNode; // [Root node only] Pointer to central node.
ImGuiDockNode* OnlyNodeWithWindows; // [Root node only] Set when there is a single visible node within the hierarchy.
int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + ImGuiDockNodeFlags_KeepAliveOnly
int LastFrameActive; // Last frame number the node was updated.
int LastFrameFocused; // Last frame number the node was focused.
- ImGuiID LastFocusedNodeID; // [Root node only] Which of our child node (any ancestor in the hierarchy) was last focused.
+ ImGuiID LastFocusedNodeID; // [Root node only] Which of our child docking node (any ancestor in the hierarchy) was last focused.
ImGuiID SelectedTabID; // [Tab node only] Which of our tab is selected.
ImGuiID WantCloseTabID; // [Tab node only] Set when closing a specific tab.
- bool InitFromFirstWindowPosSize :1;
- bool InitFromFirstWindowViewport :1;
+ ImGuiDataAutority AutorityForPos :3;
+ ImGuiDataAutority AutorityForSize :3;
+ ImGuiDataAutority AutorityForViewport :3;
bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window)
bool IsFocused :1;
- bool IsDockSpace :1; // Root node was created by a DockSpace() call.
bool IsCentralNode :1;
bool IsHiddenTabBar :1;
bool HasCloseButton :1;
@@ -789,11 +862,13 @@ struct ImGuiDockNode
bool WantCloseAll :1; // Set when closing all tabs at once.
bool WantLockSizeOnce :1;
bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created host window
+ bool WantHiddenTabBarUpdate :1;
bool WantHiddenTabBarToggle :1;
ImGuiDockNode(ImGuiID id);
~ImGuiDockNode();
bool IsRootNode() const { return ParentNode == NULL; }
+ bool IsDockSpace() const { return (Flags & ImGuiDockNodeFlags_Dockspace) != 0; }
bool IsSplitNode() const { return ChildNodes[0] != NULL; }
bool IsLeafNode() const { return ChildNodes[0] == NULL; }
bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; }
@@ -807,7 +882,8 @@ struct ImGuiDockNode
struct ImGuiContext
{
bool Initialized;
- bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame()/Render()
+ bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame()
+ bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame()
bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
ImGuiIO IO;
ImGuiPlatformIO PlatformIO;
@@ -833,7 +909,7 @@ struct ImGuiContext
ImGuiWindow* CurrentWindow; // Being drawn into
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
- ImGuiWindow* HoveredWindowUnderMovingWindow;
+ ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
ImGuiID HoveredId; // Hovered widget
bool HoveredIdAllowOverlap;
ImGuiID HoveredIdPreviousFrame;
@@ -849,6 +925,7 @@ struct ImGuiContext
bool ActiveIdPreviousFrameIsAlive;
bool ActiveIdPreviousFrameHasBeenEdited;
int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it)
+ int ActiveIdBlockNavInputFlags;
ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
ImGuiWindow* ActiveIdWindow;
ImGuiWindow* ActiveIdPreviousFrameWindow;
@@ -861,7 +938,7 @@ struct ImGuiContext
ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
ImVector FontStack; // Stack for PushFont()/PopFont()
ImVector OpenPopupStack; // Which popups are open (persistent)
- ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame)
+ ImVector BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions
ImGuiCond NextTreeNodeOpenCond;
@@ -892,7 +969,7 @@ struct ImGuiContext
float NavWindowingTimer;
float NavWindowingHighlightAlpha;
bool NavWindowingToggleLayer;
- int NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
+ ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
@@ -986,7 +1063,7 @@ struct ImGuiContext
ImGuiContext(ImFontAtlas* shared_font_atlas)
{
Initialized = false;
- FrameScopeActive = false;
+ FrameScopeActive = FrameScopePushedImplicitWindow = false;
ConfigFlagsForFrame = ImGuiConfigFlags_None;
Font = NULL;
FontSize = FontBaseSize = 0.0f;
@@ -1001,6 +1078,7 @@ struct ImGuiContext
CurrentWindow = NULL;
HoveredWindow = NULL;
HoveredRootWindow = NULL;
+ HoveredWindowUnderMovingWindow = NULL;
HoveredId = 0;
HoveredIdAllowOverlap = false;
HoveredIdPreviousFrame = 0;
@@ -1014,7 +1092,8 @@ struct ImGuiContext
ActiveIdHasBeenEdited = false;
ActiveIdPreviousFrameIsAlive = false;
ActiveIdPreviousFrameHasBeenEdited = false;
- ActiveIdAllowNavDirFlags = 0;
+ ActiveIdAllowNavDirFlags = 0x00;
+ ActiveIdBlockNavInputFlags = 0x00;
ActiveIdClickOffset = ImVec2(-1,-1);
ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL;
ActiveIdSource = ImGuiInputSource_None;
@@ -1038,7 +1117,7 @@ struct ImGuiContext
NavWindowingTarget = NavWindowingTargetAnim = NavWindowingList = NULL;
NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
NavWindowingToggleLayer = false;
- NavLayer = 0;
+ NavLayer = ImGuiNavLayer_Main;
NavIdTabCounter = INT_MAX;
NavIdIsAlive = false;
NavMousePosDirty = false;
@@ -1119,12 +1198,12 @@ struct IMGUI_API ImGuiWindowTempData
ImGuiItemStatusFlags LastItemStatusFlags;
ImRect LastItemRect; // Interaction rect
ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
- bool NavHideHighlightOneFrame;
- bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
- int NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
+ ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping.
int NavLayerActiveMask; // Which layer have been written to (result from previous frame)
int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame)
+ bool NavHideHighlightOneFrame;
+ bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
bool MenuBarAppending; // FIXME: Remove this
ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
ImVector ChildWindows;
@@ -1140,7 +1219,7 @@ struct IMGUI_API ImGuiWindowTempData
ImVector ItemWidthStack;
ImVector TextWrapPosStack;
ImVectorGroupStack;
- int StackSizesBackup[6]; // Store size of various stacks for asserting
+ short StackSizesBackup[6]; // Store size of various stacks for asserting
ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
ImVec1 GroupOffset;
@@ -1158,11 +1237,11 @@ struct IMGUI_API ImGuiWindowTempData
LastItemId = 0;
LastItemStatusFlags = 0;
LastItemRect = LastItemDisplayRect = ImRect();
+ NavLayerActiveMask = NavLayerActiveMaskNext = 0x00;
+ NavLayerCurrent = ImGuiNavLayer_Main;
+ NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
NavHideHighlightOneFrame = false;
NavHasScroll = false;
- NavLayerActiveMask = NavLayerActiveMaskNext = 0x00;
- NavLayerCurrent = 0;
- NavLayerCurrentMask = 1 << 0;
MenuBarAppending = false;
MenuBarOffset = ImVec2(0.0f, 0.0f);
StateStorage = NULL;
@@ -1183,8 +1262,9 @@ struct IMGUI_API ImGuiWindowTempData
struct IMGUI_API ImGuiWindow
{
char* Name;
- ImGuiID ID; // == ImHash(Name)
+ ImGuiID ID; // == ImHashStr(Name)
ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_
+ ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass()
ImGuiViewportP* Viewport; // Always set in Begin(), only inactive windows may have a NULL value here
ImGuiID ViewportId; // We backup the viewport id (since the viewport may disappear or never be created if the window is inactive)
ImVec2 ViewportPos; // We backup the viewport position (since the viewport may disappear or never be created if the window is inactive)
@@ -1198,6 +1278,7 @@ struct IMGUI_API ImGuiWindow
ImVec2 WindowPadding; // Window padding at the time of begin.
float WindowRounding; // Window rounding at the time of begin.
float WindowBorderSize; // Window border size at the time of begin.
+ int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)!
ImGuiID MoveId; // == window->GetID("#MOVE")
ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window)
ImVec2 Scroll;
@@ -1215,9 +1296,10 @@ struct IMGUI_API ImGuiWindow
bool Appearing; // Set during the frame where the window is appearing (or re-appearing)
bool Hidden; // Do not display (== (HiddenFramesForResize > 0) ||
bool HasCloseButton; // Set when the window has a close button (p_open != NULL)
- int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
- int BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
- int BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
+ signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3)
+ short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
+ short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
+ short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
int AutoFitFramesX, AutoFitFramesY;
bool AutoFitOnlyGrows;
@@ -1231,7 +1313,6 @@ struct IMGUI_API ImGuiWindow
ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use.
ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right.
- ImGuiDockFamily DockFamily; // set with SetNextWindowDockFamily()
ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name.
ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack
@@ -1258,8 +1339,8 @@ struct IMGUI_API ImGuiWindow
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)
- ImGuiID NavLastIds[2]; // Last known NavId for this window, per layer (0/1)
- ImRect NavRectRel[2]; // Reference rectangle, in window relative space
+ ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1)
+ ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space
// Navigation / Focus
// FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext
@@ -1314,22 +1395,20 @@ struct ImGuiItemHoveredDataBackup
};
//-----------------------------------------------------------------------------
-// Tab Bar, Tab Item
+// Tab bar, tab item
//-----------------------------------------------------------------------------
enum ImGuiTabBarFlagsPrivate_
{
- ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node
- ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // Part of an explicit dockspace node node
- ImGuiTabBarFlags_IsFocused = 1 << 22,
- ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
+ ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node
+ ImGuiTabBarFlags_IsFocused = 1 << 21,
+ ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
};
enum ImGuiTabItemFlagsPrivate_
{
- ImGuiTabItemFlags_DockedWindow = 1 << 20, // [Docking]
- ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
- ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar)
+ ImGuiTabItemFlags_Unsorted = 1 << 20, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
+ ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar)
};
// Storage for one active tab item (sizeof() 32~40 bytes)
@@ -1337,14 +1416,14 @@ struct ImGuiTabItem
{
ImGuiID ID;
ImGuiTabItemFlags Flags;
- ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window.
+ ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window.
int LastFrameVisible;
- int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
- float Offset; // Position relative to beginning of tab
- float Width; // Width currently displayed
- float WidthContents; // Width of actual contents, stored during BeginTabItem() call
+ int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
+ float Offset; // Position relative to beginning of tab
+ float Width; // Width currently displayed
+ float WidthContents; // Width of actual contents, stored during BeginTabItem() call
- ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; }
+ ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; }
};
// Storage for a tab bar (sizeof() 92~96 bytes)
@@ -1371,7 +1450,7 @@ struct ImGuiTabBar
short LastTabItemIdx; // For BeginTabItem()/EndTabItem()
ImGuiTabBar();
- int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_pointer(tab); }
+ int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); }
};
//-----------------------------------------------------------------------------
@@ -1415,10 +1494,10 @@ namespace ImGui
// NewFrame
IMGUI_API void UpdateHoveredWindowAndCaptureFlags();
IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
- IMGUI_API void UpdateMouseMovingWindow();
+ IMGUI_API void UpdateMouseMovingWindowNewFrame();
+ IMGUI_API void UpdateMouseMovingWindowEndFrame();
// Viewports
- IMGUI_API ImGuiViewportP* FindViewportByID(ImGuiID id);
IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale);
IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport);
IMGUI_API void ShowViewportThumbnails();
@@ -1459,10 +1538,9 @@ namespace ImGui
// Popups, Modals, Tooltips
IMGUI_API void OpenPopupEx(ImGuiID id);
- IMGUI_API void ClosePopup(ImGuiID id);
- IMGUI_API void ClosePopupToLevel(int remaining);
+ IMGUI_API void ClosePopupToLevel(int remaining, bool apply_focus_to_window_under);
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window);
- IMGUI_API bool IsPopupOpen(ImGuiID id);
+ IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack!
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true);
IMGUI_API ImGuiWindow* GetFrontMostPopupModal();
@@ -1496,7 +1574,6 @@ namespace ImGui
IMGUI_API void DockContextRebuild(ImGuiContext* ctx);
IMGUI_API void DockContextNewFrameUpdateUndocking(ImGuiContext* ctx);
IMGUI_API void DockContextNewFrameUpdateDocking(ImGuiContext* ctx);
- IMGUI_API void DockContextEndFrame(ImGuiContext* ctx);
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
@@ -1510,10 +1587,12 @@ namespace ImGui
IMGUI_API void DockBuilderDockWindow(const char* window_name, ImGuiID node_id);
IMGUI_API ImGuiDockNode*DockBuilderGetNode(ImGuiID node_id); // Warning: DO NOT HOLD ON ImGuiDockNode* pointer, will be invalided by any split/merge/remove operation.
inline ImGuiDockNode* DockBuilderGetCentralNode(ImGuiID node_id) { ImGuiDockNode* node = DockBuilderGetNode(node_id); if (!node) return NULL; return DockNodeGetRootNode(node)->CentralNode; }
- IMGUI_API void DockBuilderAddNode(ImGuiID node_id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0);
+ IMGUI_API ImGuiID DockBuilderAddNode(ImGuiID node_id, ImGuiDockNodeFlags flags = 0);
IMGUI_API void DockBuilderRemoveNode(ImGuiID node_id); // Remove node and all its child, undock all windows
IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiID node_id, bool clear_persistent_docking_references = true);
IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the root.
+ IMGUI_API void DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos);
+ IMGUI_API void DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size);
IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_dir, ImGuiID* out_id_other);
IMGUI_API void DockBuilderCopyDockspace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector* in_window_remap_pairs);
IMGUI_API void DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector* out_node_remap_pairs);
@@ -1533,7 +1612,7 @@ namespace ImGui
// Tab Bars
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node);
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
- IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window, ImGuiTabItemFlags tab_flags = ImGuiTabItemFlags_None);
+ IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window);
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
@@ -1565,7 +1644,7 @@ namespace ImGui
IMGUI_API void RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col);
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding);
- IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col);
+ IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col);
// Widgets
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
@@ -1584,7 +1663,7 @@ namespace ImGui
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging
IMGUI_API void TreePushRawID(ImGuiID id);
- // Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
+ // Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
// e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); "
template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, const T v_min, const T v_max, const char* format, float power, ImGuiDragFlags flags);
@@ -1614,11 +1693,23 @@ namespace ImGui
IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
-IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc);
+IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
+// Test engine hooks (imgui-test)
+//#define IMGUI_ENABLE_TEST_ENGINE
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx);
+extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx);
+extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id);
+extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);
+#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags
+#else
+#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0)
+#endif
+
#ifdef __clang__
#pragma clang diagnostic pop
#endif
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index 7a59a9d3..404d92ef 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.67 WIP
+// dear imgui, v1.68 WIP
// (widgets code)
/*
@@ -52,8 +52,16 @@ Index of this file:
// Clang/GCC warnings with -Weverything
#ifdef __clang__
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
+#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
+#endif
+#if __has_warning("-Wdouble-promotion")
+#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
+#endif
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
#if __GNUC__ >= 8
@@ -204,7 +212,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end)
}
ImRect bb(text_pos, text_pos + text_size);
- ItemSize(bb);
+ ItemSize(text_size);
ItemAdd(bb, 0);
}
else
@@ -282,10 +290,12 @@ void ImGui::TextWrapped(const char* fmt, ...)
void ImGui::TextWrappedV(const char* fmt, va_list args)
{
- bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set
- if (need_wrap) PushTextWrapPos(0.0f);
+ bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
+ if (need_backup)
+ PushTextWrapPos(0.0f);
TextV(fmt, args);
- if (need_wrap) PopTextWrapPos();
+ if (need_backup)
+ PopTextWrapPos();
}
void ImGui::LabelText(const char* label, const char* fmt, ...)
@@ -397,6 +407,11 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (flatten_hovered_children)
g.HoveredWindow = window;
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ if (id != 0 && window->DC.LastItemId != id)
+ ImGuiTestEngineHook_ItemAdd(&g, bb, id);
+#endif
+
bool pressed = false;
bool hovered = ItemHoverable(bb, id);
@@ -484,7 +499,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
// Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
g.NavActivateId = id; // This is so SetActiveId assign a Nav source
SetActiveID(id, window);
- if (!(flags & ImGuiButtonFlags_NoNavFocus))
+ if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus))
SetFocusID(id, window);
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
}
@@ -542,7 +557,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect bb(pos, pos + size);
- ItemSize(bb, style.FramePadding.y);
+ ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
@@ -563,6 +578,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup();
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
return pressed;
}
@@ -596,7 +612,7 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg)
const ImGuiID id = window->GetID(str_id);
ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
- ItemSize(bb);
+ ItemSize(size);
if (!ItemAdd(bb, id))
return false;
@@ -660,7 +676,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
// Render
ImVec2 center = bb.GetCenter();
if (hovered)
- window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9);
+ window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9);
float cross_extent = (radius * 0.7071f) - 1.0f;
ImU32 cross_col = GetColorU32(ImGuiCol_Text);
@@ -697,7 +713,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no
if (IsItemActive() && IsMouseDragging(0))
{
bool can_extract_dock_node = false;
- if (dock_node != NULL)
+ if (dock_node != NULL && dock_node->VisibleWindow && !(dock_node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove))
{
ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node);
if (root_node->OnlyNodeWithWindows != dock_node || (root_node->CentralNode != NULL))
@@ -946,6 +962,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (label_size.x > 0.0f)
RenderText(text_bb.Min, label);
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
@@ -1362,7 +1379,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
}
char name[16];
- ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
+ ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
// Peak into expected window size so we can position it
if (ImGuiWindow* popup_window = FindWindowByName(name))
@@ -1473,7 +1490,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* const items[
return value_changed;
}
-// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0"
+// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0"
bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
{
int items_count = 0;
@@ -1683,7 +1700,7 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
if (decimal_precision < 0)
return FLT_MIN;
- return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision);
+ return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision);
}
template
@@ -1744,6 +1761,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
const bool has_min_max = (v_min != v_max);
+ const bool is_power = (power != 1.0f && is_decimal && has_min_max && (v_max - v_min < FLT_MAX));
// Default tweak speed
if (v_speed == 0.0f && has_min_max && (v_max - v_min < FLT_MAX))
@@ -1775,7 +1793,8 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
// Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.
bool is_just_activated = g.ActiveIdIsJustActivated;
bool is_already_past_limits_and_pushing_outward = has_min_max && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
- if (is_just_activated || is_already_past_limits_and_pushing_outward)
+ bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0));
+ if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power)
{
g.DragCurrentAccum = 0.0f;
g.DragCurrentAccumDirty = false;
@@ -1792,7 +1811,6 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
TYPE v_cur = *v;
FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f;
- const bool is_power = (power != 1.0f && is_decimal && has_min_max && (v_max - v_min < FLT_MAX));
if (is_power)
{
// Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range
@@ -1943,6 +1961,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
return value_changed;
}
@@ -2382,6 +2401,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
return value_changed;
}
@@ -2591,7 +2611,7 @@ const char* ImParseFormatFindEnd(const char* fmt)
// fmt = "%.3f" -> return fmt
// fmt = "hello %.3f" -> return fmt + 6
// fmt = "%.3f hello" -> return buf written with "%.3f"
-const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size)
+const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size)
{
const char* fmt_start = ImParseFormatFindStart(fmt);
if (fmt_start[0] != '%')
@@ -2599,7 +2619,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_siz
const char* fmt_end = ImParseFormatFindEnd(fmt_start);
if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data.
return fmt_start;
- ImStrncpy(buf, fmt_start, ImMin((int)(fmt_end + 1 - fmt_start), buf_size));
+ ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size));
return buf;
}
@@ -2628,17 +2648,15 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
}
// Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets)
-// FIXME: Logic is awkward and confusing. This should be reworked to facilitate using in other situations.
+// FIXME: Facilitate using this in variety of other situations.
bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
{
ImGuiContext& g = *GImGui;
- ImGuiWindow* window = GetCurrentWindow();
- // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
- // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id
- SetActiveID(g.ScalarAsInputTextId, window);
- SetHoveredID(0);
- g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
+ // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id.
+ // We clear ActiveID on the first frame to allow the InputText() taking it back.
+ if (g.ScalarAsInputTextId == 0)
+ ClearActiveID();
char fmt_buf[32];
char data_buf[32];
@@ -2647,18 +2665,18 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c
ImStrTrimBlanks(data_buf);
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags);
- if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget
+ if (g.ScalarAsInputTextId == 0)
{
- IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID
+ // First frame we started displaying the InputText widget, we expect it to take the active id.
+ IM_ASSERT(g.ActiveId == id);
g.ScalarAsInputTextId = g.ActiveId;
- SetHoveredID(id);
}
if (value_changed)
return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.Data, data_type, data_ptr, NULL);
return false;
}
-bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2675,9 +2693,9 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format);
bool value_changed = false;
- if ((extra_flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
- extra_flags |= ImGuiInputTextFlags_CharsDecimal;
- extra_flags |= ImGuiInputTextFlags_AutoSelectAll;
+ if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
+ flags |= ImGuiInputTextFlags_CharsDecimal;
+ flags |= ImGuiInputTextFlags_AutoSelectAll;
if (step != NULL)
{
@@ -2686,19 +2704,22 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
PushID(label);
PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
- if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view
+ if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format);
PopItemWidth();
// Step buttons
+ ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups;
+ if (flags & ImGuiInputTextFlags_ReadOnly)
+ button_flags |= ImGuiButtonFlags_Disabled;
SameLine(0, style.ItemInnerSpacing.x);
- if (ButtonEx("-", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
+ if (ButtonEx("-", ImVec2(button_size, button_size), button_flags))
{
DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
value_changed = true;
}
SameLine(0, style.ItemInnerSpacing.x);
- if (ButtonEx("+", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
+ if (ButtonEx("+", ImVec2(button_size, button_size), button_flags))
{
DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
value_changed = true;
@@ -2711,14 +2732,14 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
}
else
{
- if (InputText(label, buf, IM_ARRAYSIZE(buf), extra_flags))
+ if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format);
}
return value_changed;
}
-bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2733,7 +2754,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
for (int i = 0; i < components; i++)
{
PushID(i);
- value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, extra_flags);
+ value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, flags);
SameLine(0, g.Style.ItemInnerSpacing.x);
PopID();
PopItemWidth();
@@ -2746,88 +2767,88 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
return value_changed;
}
-bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags)
{
- extra_flags |= ImGuiInputTextFlags_CharsScientific;
- return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags);
+ flags |= ImGuiInputTextFlags_CharsScientific;
+ return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, flags);
}
-bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags)
{
- return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags);
+ return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags);
}
-bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags)
{
- return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags);
+ return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags);
}
-bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags)
{
- return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags);
+ return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags);
}
// Prefer using "const char* format" directly, which is more flexible and consistent with other API.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags)
{
char format[16] = "%f";
if (decimal_precision >= 0)
ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
- return InputFloat(label, v, step, step_fast, format, extra_flags);
+ return InputFloat(label, v, step, step_fast, format, flags);
}
-bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags)
{
char format[16] = "%f";
if (decimal_precision >= 0)
ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
- return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags);
+ return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags);
}
-bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags)
{
char format[16] = "%f";
if (decimal_precision >= 0)
ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
- return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags);
+ return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags);
}
-bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags)
{
char format[16] = "%f";
if (decimal_precision >= 0)
ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
- return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags);
+ return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags);
}
#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags)
{
// Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
- const char* format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
- return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags);
+ const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
+ return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, flags);
}
-bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags)
+bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags)
{
- return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", extra_flags);
+ return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags);
}
-bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags)
+bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags)
{
- return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", extra_flags);
+ return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags);
}
-bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags)
+bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags)
{
- return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", extra_flags);
+ return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags);
}
-bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags extra_flags)
+bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags)
{
- extra_flags |= ImGuiInputTextFlags_CharsScientific;
- return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags);
+ flags |= ImGuiInputTextFlags_CharsScientific;
+ return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, flags);
}
//-------------------------------------------------------------------------
@@ -3134,7 +3155,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
// Edit a string of text
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
-// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
+// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator.
// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect.
// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h
@@ -3149,7 +3170,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
ImGuiContext& g = *GImGui;
- const ImGuiIO& io = g.IO;
+ ImGuiIO& io = g.IO;
const ImGuiStyle& style = g.Style;
const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
@@ -3160,7 +3181,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (is_resizable)
IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag!
- if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
+ if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope,
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
@@ -3265,8 +3286,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
+ g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel);
if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
- g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
+ g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
}
else if (io.MouseClicked[0])
{
@@ -3334,22 +3356,22 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
edit_state.SelectedAllMouseLock = false;
- if (io.InputCharacters[0])
+ if (io.InputQueueCharacters.Size > 0)
{
// Process text input (before we check for Return because using some IME will effectively send a Return?)
// We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters.
bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
if (!ignore_inputs && is_editable && !user_nav_input_start)
- for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
+ for (int n = 0; n < io.InputQueueCharacters.Size; n++)
{
// Insert character if they pass filtering
- unsigned int c = (unsigned int)io.InputCharacters[n];
+ unsigned int c = (unsigned int)io.InputQueueCharacters[n];
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
edit_state.OnKeyPressed((int)c);
}
// Consume characters
- memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
+ io.InputQueueCharacters.resize(0);
}
}
@@ -3596,7 +3618,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
}
// If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size.
- ImStrncpy(buf, edit_state.TempBuffer.Data, ImMin(apply_new_text_length + 1, buf_size));
+ ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));
value_changed = true;
}
@@ -3805,6 +3827,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (value_changed)
MarkItemEdited(id);
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
return enter_pressed;
else
@@ -3911,9 +3934,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if (n + 1 == components)
PushItemWidth(w_item_last);
if (flags & ImGuiColorEditFlags_Float)
- value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
+ {
+ value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
+ value_changed_as_float |= value_changed;
+ }
else
+ {
value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
+ }
if (!(flags & ImGuiColorEditFlags_NoOptions))
OpenPopupOnItemClick("context");
}
@@ -4016,7 +4044,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
{
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
{
- memcpy((float*)col, payload->Data, sizeof(float) * 3);
+ memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512
value_changed = true;
}
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
@@ -4598,7 +4626,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask);
SetCursorScreenPos(backup_pos);
ImVec4 dummy_ref_col;
- memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4));
+ memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4));
ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags);
PopID();
}
@@ -4619,7 +4647,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
// - TreeNodeV()
// - TreeNodeEx()
// - TreeNodeExV()
-// - TreeNodeBehavior() [Internal]
+// - TreeNodeBehavior() [Internal]
// - TreePush()
// - TreePop()
// - TreeAdvanceToLabelPos()
@@ -4794,6 +4822,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not)
const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y);
bool is_open = TreeNodeBehaviorIsOpen(id, flags);
+ bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
// Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child.
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
@@ -4809,6 +4838,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
{
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushRawID(id);
+ IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open;
}
@@ -4818,13 +4848,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// - OpenOnArrow .................... single-click on arrow to open
// - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0);
- if (!(flags & ImGuiTreeNodeFlags_Leaf))
+ if (!is_leaf)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0);
bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
- if (!(flags & ImGuiTreeNodeFlags_Leaf))
+ if (!is_leaf)
{
bool toggled = false;
if (pressed)
@@ -4892,7 +4922,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (flags & ImGuiTreeNodeFlags_Bullet)
RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
- else if (!(flags & ImGuiTreeNodeFlags_Leaf))
+ else if (!is_leaf)
RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
if (g.LogEnabled)
LogRenderedText(&text_pos, ">");
@@ -4901,6 +4931,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushRawID(id);
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open;
}
@@ -4998,7 +5029,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags
ImGuiItemHoveredDataBackup last_item_backup;
float button_radius = g.FontSize * 0.5f;
ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y);
- if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), button_center, button_radius))
+ if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius))
*p_open = false;
last_item_backup.Restore();
}
@@ -5052,7 +5083,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
bb.Min.y -= spacing_U;
bb.Max.x += spacing_R;
bb.Max.y += spacing_D;
- if (!ItemAdd(bb, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id))
+ if (!ItemAdd(bb, id))
{
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
PushColumnClipRect();
@@ -5493,7 +5524,7 @@ bool ImGui::BeginMainMenuBar()
End();
return false;
}
- return true;
+ return true; //-V1020
}
void ImGui::EndMainMenuBar()
@@ -5523,14 +5554,14 @@ bool ImGui::BeginMenuBar()
// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
// We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
ImRect bar_rect = window->MenuBarRect();
- ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f));
+ ImRect clip_rect(ImFloor(bar_rect.Min.x + window->WindowBorderSize + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize)) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f));
clip_rect.ClipWith(window->OuterRectClipped);
PushClipRect(clip_rect.Min, clip_rect.Max, false);
window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y);
window->DC.LayoutType = ImGuiLayoutType_Horizontal;
- window->DC.NavLayerCurrent++;
- window->DC.NavLayerCurrentMask <<= 1;
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
window->DC.MenuBarAppending = true;
AlignTextToFramePadding();
return true;
@@ -5556,7 +5587,7 @@ void ImGui::EndMenuBar()
IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check
FocusWindow(window);
SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]);
- g.NavLayer = 1;
+ g.NavLayer = ImGuiNavLayer_Menu;
g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
NavMoveRequestCancel();
@@ -5571,8 +5602,8 @@ void ImGui::EndMenuBar()
window->DC.GroupStack.back().AdvanceCursor = false;
EndGroup(); // Restore position on layer 0
window->DC.LayoutType = ImGuiLayoutType_Vertical;
- window->DC.NavLayerCurrent--;
- window->DC.NavLayerCurrentMask >>= 1;
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
window->DC.MenuBarAppending = false;
}
@@ -5590,7 +5621,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
bool pressed;
bool menu_is_open = IsPopupOpen(id);
- bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back());
+ bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back());
ImGuiWindow* backed_nav_window = g.NavWindow;
if (menuset_is_open)
g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
@@ -5631,9 +5662,9 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
{
// Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
bool moving_within_opened_triangle = false;
- if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar))
+ if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar))
{
- if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window)
+ if (ImGuiWindow* next_window = g.OpenPopupStack[g.BeginPopupStack.Size].Window)
{
ImRect next_window_rect = next_window->Rect();
ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
@@ -5684,9 +5715,11 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
want_close = true;
if (want_close && IsPopupOpen(id))
- ClosePopupToLevel(g.CurrentPopupStack.Size);
+ ClosePopupToLevel(g.BeginPopupStack.Size, true);
- if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size)
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
+
+ if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size)
{
// Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
OpenPopup(label);
@@ -5712,14 +5745,14 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
void ImGui::EndMenu()
{
- // Nav: When a left move request _within our child menu_ failed, close the menu.
+ // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu).
// A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
// However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
{
- ClosePopupToLevel(g.OpenPopupStack.Size - 1);
+ ClosePopupToLevel(g.BeginPopupStack.Size, true);
NavMoveRequestCancel();
}
@@ -5765,6 +5798,8 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo
if (selected)
RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f);
}
+
+ IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
@@ -5782,6 +5817,8 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
//-------------------------------------------------------------------------
// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.
//-------------------------------------------------------------------------
+// [BETA API] API may evolve!
+//-------------------------------------------------------------------------
// - BeginTabBar()
// - BeginTabBarEx() [Internal]
// - EndTabBar()
@@ -5815,6 +5852,7 @@ ImGuiTabBar::ImGuiTabBar()
ID = 0;
SelectedTabId = NextSelectedTabId = VisibleTabId = 0;
CurrFrameVisible = PrevFrameVisible = -1;
+ ContentsHeight = 0.0f;
OffsetMax = OffsetNextTab = 0.0f;
ScrollingAnim = ScrollingTarget = 0.0f;
Flags = ImGuiTabBarFlags_None;
@@ -5867,12 +5905,12 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
g.CurrentTabBar.push_back(tab_bar);
if (tab_bar->CurrFrameVisible == g.FrameCount)
{
- printf("[%05d] BeginTabBarEx already called this frame\n", g.FrameCount);
+ //IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount);
//IM_ASSERT(0);
return true;
}
- // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order.
+ // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order.
// Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user.
if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1)
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset);
@@ -5887,7 +5925,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible;
tab_bar->CurrFrameVisible = g.FrameCount;
- // Layout
+ // Layout
ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight()));
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
@@ -5896,14 +5934,14 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
const float y = tab_bar->BarRect.Max.y - 1.0f;
if (dock_node != NULL)
{
- const float separator_min_x = dock_node->Pos.x;
- const float separator_max_x = dock_node->Pos.x + dock_node->Size.x;
+ const float separator_min_x = dock_node->Pos.x + window->WindowBorderSize;
+ const float separator_max_x = dock_node->Pos.x + dock_node->Size.x - window->WindowBorderSize;
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
}
else
{
- const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x);
- const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x);
+ const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x;
+ const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x;
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
}
return true;
@@ -5972,7 +6010,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
{
if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId))
{
- IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable);
+ //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools
int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir;
if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size)
{
@@ -6008,7 +6046,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
found_selected_tab_id = true;
// Refresh tab width immediately if we can (for manual tab bar, WidthContent will lag by one frame which is mostly noticeable when changing style.FramePadding.x)
- // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
+ // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
if (tab->Window)
tab->WidthContents = TabItemCalcSize(tab->Window->Name, tab->Window->HasCloseButton).x;
@@ -6106,7 +6144,7 @@ static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label)
{
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
{
- ImGuiID id = ImHash(label, 0);
+ ImGuiID id = ImHashStr(label, 0);
KeepAliveID(id);
return id;
}
@@ -6134,7 +6172,7 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)
// The purpose of this call is to register tab in advance so we can control their order at the time they appear.
// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function.
-void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window, ImGuiTabItemFlags tab_flags)
+void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL);
@@ -6298,6 +6336,8 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
//-------------------------------------------------------------------------
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
//-------------------------------------------------------------------------
+// [BETA API] API may evolve!
+//-------------------------------------------------------------------------
// - BeginTabItem()
// - EndTabItem()
// - TabItemEx() [Internal]
@@ -6317,7 +6357,10 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
ImGuiTabBar* tab_bar = g.CurrentTabBar.back();
bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
- PushID(tab_bar->Tabs[tab_bar->LastTabItemIdx].ID);
+ {
+ ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
+ g.CurrentWindow->IDStack.push_back(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label)
+ }
return ret;
}
@@ -6329,9 +6372,10 @@ void ImGui::EndTabItem()
IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!");
ImGuiTabBar* tab_bar = g.CurrentTabBar.back();
+ IM_ASSERT(tab_bar->LastTabItemIdx >= 0 && "Needs to be called between BeginTabItem() and EndTabItem()");
ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
if (!(tab->Flags & ImGuiTabItemFlags_NoPushId))
- PopID();
+ g.CurrentWindow->IDStack.pop_back();
}
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
@@ -6371,7 +6415,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
tab->Width = size.x;
tab_is_new = true;
}
- tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_pointer(tab);
+ tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab);
tab->WidthContents = size.x;
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
@@ -6455,19 +6499,18 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Drag and drop a single floating window node moves it
// FIXME-DOCK: In theory we shouldn't test for the ConfigDockingNodifySingleWindows flag here.
// When our single window node and OnlyNodeWithWindows are working properly we may remove this check here.
- ImGuiDockNode* node = docked_window->DockNode;
- const bool single_window_node = node->IsRootNode() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows;
- if (held && single_window_node && IsMouseDragging(0, 0.0f))
+ ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL;
+ const bool single_floating_window_node = node && node->IsRootNode() && !node->IsDockSpace() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows;
+ if (held && single_floating_window_node && IsMouseDragging(0, 0.0f))
{
// Move
StartMouseMovingWindow(docked_window);
}
else if (held && !tab_appearing && IsMouseDragging(0))
{
- // Drag and drop
- // Re-order local or dockable tabs
+ // Drag and drop: re-order tabs
float drag_distance_from_edge_x = 0.0f;
- if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (flags & ImGuiTabItemFlags_DockedWindow)))
+ if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL)))
{
// While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x)
@@ -6485,27 +6528,25 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
}
// Extract a Dockable window out of it's tab bar
- if (flags & ImGuiTabItemFlags_DockedWindow)
+ if (docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove))
{
// We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar
bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id);
- if (!undocking_tab && held)
+
+ if (!undocking_tab) //&& (!g.IO.ConfigDockingWithShift || g.IO.KeyShift)
{
- //if (!g.IO.ConfigDockingWithShift || g.IO.KeyShift)
- {
- float threshold_base = g.FontSize;
- //float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize;
- float threshold_x = (threshold_base * 2.2f);
- float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f);
- //GetOverlayDrawList(window)->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG]
-
- float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y);
- if (distance_from_edge_y >= threshold_y)
+ float threshold_base = g.FontSize;
+ //float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize;
+ float threshold_x = (threshold_base * 2.2f);
+ float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f);
+ //GetOverlayDrawList(window)->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG]
+
+ float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y);
+ if (distance_from_edge_y >= threshold_y)
+ undocking_tab = true;
+ else if (drag_distance_from_edge_x > threshold_x)
+ if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1))
undocking_tab = true;
- else if (drag_distance_from_edge_x > threshold_x)
- if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1))
- undocking_tab = true;
- }
}
if (undocking_tab)
@@ -6544,9 +6585,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
// Render tab label, process close button
- const ImGuiID close_button_id = p_open ? window->GetID((void*)(intptr_t)(id + 1)) : 0;
+ const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0;
bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id);
- if (just_closed)
+ if (just_closed && p_open != NULL)
{
*p_open = false;
TabBarCloseTab(tab_bar, tab);
@@ -6559,7 +6600,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer)
if (g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > 0.50f)
- SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
+ if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip))
+ SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
return tab_contents_visible;
}
@@ -6606,6 +6648,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
// While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it.
ImGuiContext& g = *GImGui;
const float width = bb.GetWidth();
+ IM_UNUSED(flags);
IM_ASSERT(width > 0.0f);
const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f));
float y1 = bb.Min.y + 1.0f;
@@ -6620,7 +6663,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
draw_list->PathClear();
}
-// Render text label (with clipping + alpha gradient) + unsaved marker + Close Button logic
+// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic
bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id)
{
ImGuiContext& g = *GImGui;
@@ -6666,7 +6709,7 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
}
// Label with ellipsis
- // FIXME: This could be extracted into a helper but or use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment
+ // FIXME: This should be extracted into a helper but the use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment
const char* label_display_end = FindRenderedTextEnd(label);
if (label_size.x > text_ellipsis_clip_bb.GetWidth())
{
@@ -6688,7 +6731,7 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
const float ellipsis_x = text_pixel_clip_bb.Min.x + label_size_clipped_x + 1.0f;
if (!close_button_visible && ellipsis_x + ellipsis_width <= bb.Max.x)
- RenderPixelEllipsis(draw_list, g.Font, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text));
+ RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text));
}
else
{
diff --git a/imstb_textedit.h b/imstb_textedit.h
index 9e12469b..27e34f74 100644
--- a/imstb_textedit.h
+++ b/imstb_textedit.h
@@ -563,7 +563,6 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
// now scan to find xpos
find->x = r.x0;
- i = 0;
for (i=0; first+i < n; ++i)
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
}
diff --git a/imstb_truetype.h b/imstb_truetype.h
index f65deb50..0b65350a 100644
--- a/imstb_truetype.h
+++ b/imstb_truetype.h
@@ -1,3 +1,6 @@
+// [ImGui] this is a slightly modified version of stb_truetype.h 1.19. Those changes would need to be pushed into nothings/stb
+// grep for [ImGui] to find the changes.
+
// stb_truetype.h - v1.19 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
//
@@ -1825,7 +1828,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
if (comp_verts) STBTT_free(comp_verts, info->userdata);
return 0;
}
- if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
+ if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595
STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
if (vertices) STBTT_free(vertices, info->userdata);
vertices = tmp;
@@ -2196,7 +2199,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
} break;
default:
- if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
+ if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560
return STBTT__CSERR("reserved operator");
// push immediate
@@ -2368,7 +2371,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
- classDefTable = classDef1ValueArray + 2 * glyphCount;
+ // [ImGui: commented to fix static analyzer warning]
+ //classDefTable = classDef1ValueArray + 2 * glyphCount;
} break;
case 2: {
@@ -2392,7 +2396,8 @@ static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
}
- classDefTable = classRangeRecords + 6 * classRangeCount;
+ // [ImGui: commented to fix static analyzer warning]
+ //classDefTable = classRangeRecords + 6 * classRangeCount;
} break;
default: {
@@ -3024,6 +3029,7 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
dx = -dx;
dy = -dy;
t = x0, x0 = xb, xb = t;
+ (void)dx; // [ImGui: fix static analyzer warning]
}
x1 = (int) x_top;
@@ -4253,7 +4259,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
int winding = 0;
orig[0] = x;
- orig[1] = y;
+ //orig[1] = y; // [ImGui] commmented double assignment without reading
// make sure y never passes through a vertex of the shape
y_frac = (float) STBTT_fmod(y, 1.0f);
diff --git a/misc/README.txt b/misc/README.txt
index ff23d7fc..be3af5ae 100644
--- a/misc/README.txt
+++ b/misc/README.txt
@@ -13,6 +13,6 @@ misc/freetype/
Benefit from better FreeType rasterization, in particular for small fonts.
misc/natvis/
- Natvis file to describe dear imgui types in the Visual Studio debugger.
- With this, types like ImVector<> will be displayed nicely in the debugger.
+ Natvis file to describe dear imgui types in the Visual Studio debugger.
+ With this, types like ImVector<> will be displayed nicely in the debugger.
You can include this file a Visual Studio project file, or install it in Visual Studio folder.
diff --git a/misc/cpp/README.txt b/misc/cpp/README.txt
index dedfa747..9067cac0 100644
--- a/misc/cpp/README.txt
+++ b/misc/cpp/README.txt
@@ -3,7 +3,7 @@ imgui_stdlib.h + imgui_stdlib.cpp
InputText() wrappers for C++ standard library (STL) type: std::string.
This is also an example of how you may wrap your own similar types.
-imgui_scoped.h
+imgui_scoped.h
[Experimental, not currently in main repository]
Additional header file with some RAII-style wrappers for common ImGui functions.
Try by merging: https://github.com/ocornut/imgui/pull/2197
diff --git a/misc/cpp/imgui_stdlib.cpp b/misc/cpp/imgui_stdlib.cpp
index 790d8d80..694813a4 100644
--- a/misc/cpp/imgui_stdlib.cpp
+++ b/misc/cpp/imgui_stdlib.cpp
@@ -3,7 +3,7 @@
// This is also an example of how you may wrap your own similar types.
// Compatibility:
-// - std::string support is only guaranteed to work from C++11.
+// - std::string support is only guaranteed to work from C++11.
// If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture)
// Changelog:
diff --git a/misc/cpp/imgui_stdlib.h b/misc/cpp/imgui_stdlib.h
index 200c45a5..06b06b9a 100644
--- a/misc/cpp/imgui_stdlib.h
+++ b/misc/cpp/imgui_stdlib.h
@@ -3,7 +3,7 @@
// This is also an example of how you may wrap your own similar types.
// Compatibility:
-// - std::string support is only guaranteed to work from C++11.
+// - std::string support is only guaranteed to work from C++11.
// If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture)
// Changelog:
diff --git a/misc/fonts/README.txt b/misc/fonts/README.txt
index 236c3dd0..fd4ed1bf 100644
--- a/misc/fonts/README.txt
+++ b/misc/fonts/README.txt
@@ -3,7 +3,7 @@ The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' (by Tristan Grimmer),
a 13 pixels high, pixel-perfect font used by default.
We embed it font in source code so you can use Dear ImGui without any file system access.
-You may also load external .TTF/.OTF files.
+You may also load external .TTF/.OTF files.
The files in this folder are suggested fonts, provided as a convenience.
(Note: .OTF support in imstb_truetype.h currently doesn't appear to load every font)
@@ -45,9 +45,9 @@ If you have other loading/merging/adding fonts, you can post on the Dear ImGui "
USING ICONS
---------------------------------------
-Using an icon font (such as FontAwesome: http://fontawesome.io or OpenFontIcons. https://github.com/traverseda/OpenFontIcons)
+Using an icon font (such as FontAwesome: http://fontawesome.io or OpenFontIcons. https://github.com/traverseda/OpenFontIcons)
is an easy and practical way to use icons in your Dear ImGui application.
-A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without
+A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without
having to change fonts back and forth.
To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut:
@@ -77,8 +77,8 @@ Example Usage:
ImGui::Text("%s among %d items", ICON_FA_SEARCH, count);
ImGui::Button(ICON_FA_SEARCH " Search");
// C string _literals_ can be concatenated at compilation time, e.g. "hello" " world"
- // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB"
-
+ // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB"
+
See Links below for other icons fonts and related tools.
@@ -96,7 +96,7 @@ Load .TTF/.OTF file with:
ImGuiIO& io = ImGui::GetIO();
ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels);
ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels);
-
+
// Select font at runtime
ImGui::Text("Hello"); // use the default font (which is the first loaded font)
ImGui::PushFont(font2);
@@ -113,14 +113,14 @@ For advanced options create a ImFontConfig structure and pass it to the AddFont
If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API.
The typical result of failing to upload a texture is if every glyphs appears as white rectangles.
-In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you
+In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you
set OversampleH/OversampleV to 1 and use a small font size.
Mind the fact that some graphics drivers have texture size limitation.
If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours.
Some solutions:
- - 1) Reduce glyphs ranges by calculating them from source localization data. You can use ImFont::GlyphRangesBuilder for this purpose,
- this will be the biggest win.
+ - 1) Reduce glyphs ranges by calculating them from source localization data.
+ You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win!
- 2) You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size.
- 3) Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function).
- 4) Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two.
@@ -144,14 +144,14 @@ Add a fourth parameter to bake specific font ranges only:
// Basic Latin, Extended Latin
io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault());
-
+
// Default + Selection of 2500 Ideographs used by Simplified Chinese
io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
-
+
// Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
-See "BUILDING CUSTOM GLYPH RANGES" section to create your own ranges.
+See "BUILDING CUSTOM GLYPH RANGES" section to create your own ranges.
Offset font vertically by altering the io.Font->DisplayOffset value:
ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels);
@@ -163,8 +163,8 @@ Offset font vertically by altering the io.Font->DisplayOffset value:
---------------------------------------
Dear ImGui uses imstb_truetype.h to rasterize fonts (with optional oversampling).
-This technique and its implementation are not ideal for fonts rendered at _small sizes_, which may appear a
-little blurry or hard to read.
+This technique and its implementation are not ideal for fonts rendered at _small sizes_, which may appear a
+little blurry or hard to read.
There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder.
@@ -177,11 +177,11 @@ Also note that correct sRGB space blending will have an important effect on your
BUILDING CUSTOM GLYPH RANGES
---------------------------------------
-You can use the ImFontAtlas::GlyphRangesBuilder helper to create glyph ranges based on text input.
-For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs.
+You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input.
+For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs.
ImVector ranges;
- ImFontAtlas::GlyphRangesBuilder builder;
+ ImFontGlyphRangesBuilder builder;
builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
builder.AddChar(0x7262); // Add a specific character
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
@@ -198,11 +198,11 @@ For example: for a game where your script is known, if you can feed your entire
Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array that you can embed in source code.
See the documentation in binary_to_compressed_c.cpp for instruction on how to use the tool.
You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see README).
-The tool optionally used Base85 encoding to reduce the size of _source code_ but the read-only arrays will be about 20% bigger.
+The tool optionally used Base85 encoding to reduce the size of _source code_ but the read-only arrays will be about 20% bigger.
Then load the font with:
ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...);
-or:
+or:
ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...);
@@ -221,7 +221,7 @@ Cousine-Regular.ttf
by Steve Matteson
Digitized data copyright (c) 2010 Google Corporation.
Licensed under the SIL Open Font License, Version 1.1
- https://fonts.google.com/specimen/Cousine
+ https://fonts.google.com/specimen/Cousine
DroidSans.ttf
@@ -267,7 +267,7 @@ ICON FONTS
Kenney Icon Font (Game Controller Icons)
https://github.com/nicodinh/kenney-icon-font
-
+
IcoMoon - Custom Icon font builder
https://icomoon.io/app
diff --git a/misc/fonts/binary_to_compressed_c.cpp b/misc/fonts/binary_to_compressed_c.cpp
index 08b102d4..3fde3d95 100644
--- a/misc/fonts/binary_to_compressed_c.cpp
+++ b/misc/fonts/binary_to_compressed_c.cpp
@@ -56,7 +56,7 @@ int main(int argc, char** argv)
return binary_to_compressed_c(argv[argn], argv[argn+1], use_base85_encoding, use_compression) ? 0 : 1;
}
-char Encode85Byte(unsigned int x)
+char Encode85Byte(unsigned int x)
{
x = (x % 85) + 35;
return (x>='\\') ? x+1 : x;
@@ -214,7 +214,7 @@ static int stb__window = 0x40000; // 256K
static int stb_not_crap(int best, int dist)
{
- return ((best > 2 && dist <= 0x00100)
+ return ((best > 2 && dist <= 0x00100)
|| (best > 5 && dist <= 0x04000)
|| (best > 7 && dist <= 0x80000));
}
@@ -296,15 +296,15 @@ static int stb_compress_chunk(stb_uchar *history,
stb_out(dist-1);
} else if (best > 5 && best <= 0x100 && dist <= 0x4000) {
outliterals(lit_start, q-lit_start); lit_start = (q += best);
- stb_out2(0x4000 + dist-1);
+ stb_out2(0x4000 + dist-1);
stb_out(best-1);
} else if (best > 7 && best <= 0x100 && dist <= 0x80000) {
outliterals(lit_start, q-lit_start); lit_start = (q += best);
- stb_out3(0x180000 + dist-1);
+ stb_out3(0x180000 + dist-1);
stb_out(best-1);
} else if (best > 8 && best <= 0x10000 && dist <= 0x80000) {
outliterals(lit_start, q-lit_start); lit_start = (q += best);
- stb_out3(0x100000 + dist-1);
+ stb_out3(0x100000 + dist-1);
stb_out2(best-1);
} else if (best > 9 && dist <= 0x1000000) {
if (best > 65536) best = 65536;
diff --git a/misc/freetype/README.md b/misc/freetype/README.md
index ba633f69..156e6511 100644
--- a/misc/freetype/README.md
+++ b/misc/freetype/README.md
@@ -1,14 +1,14 @@
# imgui_freetype
-This is an attempt to replace stb_truetype (the default imgui's font rasterizer) with FreeType.
-Currently not optimal and probably has some limitations or bugs.
-By [Vuhdo](https://github.com/Vuhdo) (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut.
+Build font atlases using FreeType instead of stb_truetype (the default imgui's font rasterizer).
+
by @vuhdo, @mikesart, @ocornut.
-**Usage**
-1. Get latest FreeType binaries or build yourself.
+### Usage
+
+1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype`).
2. Add imgui_freetype.h/cpp alongside your imgui sources.
3. Include imgui_freetype.h after imgui.h.
-4. Call ImGuiFreeType::BuildFontAtlas() *BEFORE* calling ImFontAtlas::GetTexDataAsRGBA32() or ImFontAtlas::Build() (so normal Build() won't be called):
+4. Call `ImGuiFreeType::BuildFontAtlas()` *BEFORE* calling `ImFontAtlas::GetTexDataAsRGBA32()` or `ImFontAtlas::Build()` (so normal Build() won't be called):
```cpp
// See ImGuiFreeType::RasterizationFlags
@@ -17,13 +17,14 @@ ImGuiFreeType::BuildFontAtlas(io.Fonts, flags);
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
```
-**Gamma Correct Blending**
+### Gamma Correct Blending
+
FreeType assumes blending in linear space rather than gamma space.
See FreeType note for [FT_Render_Glyph](https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Render_Glyph).
For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
The default imgui styles will be impacted by this change (alpha values will need tweaking).
-**Test code Usage**
+### Test code Usage
```cpp
#include "misc/freetype/imgui_freetype.h"
#include "misc/freetype/imgui_freetype.cpp"
@@ -42,16 +43,15 @@ while (true)
if (freetype_test.UpdateRebuild())
{
// REUPLOAD FONT TEXTURE TO GPU
- // e.g ImGui_ImplGlfwGL3_InvalidateDeviceObjects() + ImGui_ImplGlfwGL3_CreateDeviceObjects()
+ // e.g ImGui_ImplOpenGL3_DestroyDeviceObjects() + ImGui_ImplOpenGL3_CreateDeviceObjects()
}
ImGui::NewFrame();
freetype_test.ShowFreetypeOptionsWindow();
...
- }
}
```
-**Test code**
+### Test code
```cpp
#include "misc/freetype/imgui_freetype.h"
#include "misc/freetype/imgui_freetype.cpp"
@@ -61,7 +61,7 @@ struct FreeTypeTest
enum FontBuildMode
{
FontBuildMode_FreeType,
- FontBuildMode_Stb,
+ FontBuildMode_Stb
};
FontBuildMode BuildMode;
@@ -120,14 +120,6 @@ struct FreeTypeTest
};
```
-**Known issues**
-- Output texture has excessive resolution (lots of vertical waste).
-- FreeType's memory allocator is not overridden.
+### Known issues
- `cfg.OversampleH`, `OversampleV` are ignored (but perhaps not so necessary with this rasterizer).
-**Obligatory comparison screenshots**
-
-Using Windows built-in segoeui.ttf font. Open in new browser tabs, view at 1080p+.
-
-![freetype rasterizer](https://raw.githubusercontent.com/wiki/ocornut/imgui_club/images/freetype_20170817.png)
-
diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp
index 33bdb140..f7523644 100644
--- a/misc/freetype/imgui_freetype.cpp
+++ b/misc/freetype/imgui_freetype.cpp
@@ -1,15 +1,17 @@
-// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
+// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
-// Original code by @Vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained by @ocornut
+// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained and v0.60+ by @ocornut.
// Changelog:
// - v0.50: (2017/08/16) imported from https://github.com/Vuhdo/imgui_freetype into http://www.github.com/ocornut/imgui_club, updated for latest changes in ImFontAtlas, minor tweaks.
// - v0.51: (2017/08/26) cleanup, optimizations, support for ImFontConfig::RasterizerFlags, ImFontConfig::RasterizerMultiply.
-// - v0.52: (2017/09/26) fixes for imgui internal changes
-// - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement)
-// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member
+// - v0.52: (2017/09/26) fixes for imgui internal changes.
+// - v0.53: (2017/10/22) minor inconsequential change to match change in master (removed an unnecessary statement).
+// - v0.54: (2018/01/22) fix for addition of ImFontAtlas::TexUvscale member.
// - v0.55: (2018/02/04) moved to main imgui repository (away from http://www.github.com/ocornut/imgui_club)
-// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX
+// - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX.
+// - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding.
+// - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions().
// Gamma Correct Blending:
// FreeType assumes blending in linear space rather than gamma space.
@@ -17,18 +19,16 @@
// For correct results you need to be using sRGB and convert to linear space in the pixel shader output.
// The default imgui styles will be impacted by this change (alpha values will need tweaking).
-// TODO:
-// - Output texture has excessive resolution (lots of vertical waste).
-// - FreeType's memory allocator is not overridden.
-// - cfg.OversampleH, OversampleV are ignored (but perhaps not so necessary with this rasterizer).
+// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer).
#include "imgui_freetype.h"
-#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
+#include "imgui_internal.h" // ImMin,ImMax,ImFontAtlasBuild*,
#include
#include
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-#include FT_SYNTHESIS_H
+#include FT_FREETYPE_H //
+#include FT_MODULE_H //
+#include FT_GLYPH_H //
+#include FT_SYNTHESIS_H //
#ifdef _MSC_VER
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
@@ -38,7 +38,7 @@
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#endif
-namespace
+namespace
{
// Glyph metrics:
// --------------
@@ -72,17 +72,17 @@ namespace
// |------------- advanceX ----------->|
/// A structure that describe a glyph.
- struct GlyphInfo
+ struct GlyphInfo
{
- float Width; // Glyph's width in pixels.
- float Height; // Glyph's height in pixels.
- float OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
- float OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
- float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
+ int Width; // Glyph's width in pixels.
+ int Height; // Glyph's height in pixels.
+ FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
+ FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
+ float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
};
// Font parameters and metrics.
- struct FontInfo
+ struct FontInfo
{
uint32_t PixelHeight; // Size this font was generated with.
float Ascender; // The pixel extents above the baseline in pixels (typically positive).
@@ -96,82 +96,79 @@ namespace
// NB: No ctor/dtor, explicitly call Init()/Shutdown()
struct FreeTypeFont
{
- bool Init(const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
- void Shutdown();
- void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
-
- bool CalcGlyphInfo(uint32_t codepoint, GlyphInfo& glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap);
- void BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
+ bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
+ void CloseFont();
+ void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size
+ const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
+ const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
+ void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL);
+ ~FreeTypeFont() { CloseFont(); }
// [Internals]
FontInfo Info; // Font descriptor of the current font.
+ FT_Face Face;
unsigned int UserFlags; // = ImFontConfig::RasterizerFlags
- FT_Library FreetypeLibrary;
- FT_Face FreetypeFace;
- FT_Int32 FreetypeLoadFlags;
+ FT_Int32 LoadFlags;
};
// From SDL_ttf: Handy routines for converting from fixed point
#define FT_CEIL(X) (((X + 63) & -64) / 64)
- bool FreeTypeFont::Init(const ImFontConfig& cfg, unsigned int extra_user_flags)
+ bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags)
{
- // FIXME: substitute allocator
- FT_Error error = FT_Init_FreeType(&FreetypeLibrary);
- if (error != 0)
- return false;
- error = FT_New_Memory_Face(FreetypeLibrary, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &FreetypeFace);
+ FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face);
if (error != 0)
return false;
- error = FT_Select_Charmap(FreetypeFace, FT_ENCODING_UNICODE);
+ error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
if (error != 0)
return false;
memset(&Info, 0, sizeof(Info));
SetPixelHeight((uint32_t)cfg.SizePixels);
- // Convert to freetype flags (nb: Bold and Oblique are processed separately)
+ // Convert to FreeType flags (NB: Bold and Oblique are processed separately)
UserFlags = cfg.RasterizerFlags | extra_user_flags;
- FreetypeLoadFlags = FT_LOAD_NO_BITMAP;
- if (UserFlags & ImGuiFreeType::NoHinting) FreetypeLoadFlags |= FT_LOAD_NO_HINTING;
- if (UserFlags & ImGuiFreeType::NoAutoHint) FreetypeLoadFlags |= FT_LOAD_NO_AUTOHINT;
- if (UserFlags & ImGuiFreeType::ForceAutoHint) FreetypeLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
- if (UserFlags & ImGuiFreeType::LightHinting)
- FreetypeLoadFlags |= FT_LOAD_TARGET_LIGHT;
- else if (UserFlags & ImGuiFreeType::MonoHinting)
- FreetypeLoadFlags |= FT_LOAD_TARGET_MONO;
- else
- FreetypeLoadFlags |= FT_LOAD_TARGET_NORMAL;
+ LoadFlags = FT_LOAD_NO_BITMAP;
+ if (UserFlags & ImGuiFreeType::NoHinting)
+ LoadFlags |= FT_LOAD_NO_HINTING;
+ if (UserFlags & ImGuiFreeType::NoAutoHint)
+ LoadFlags |= FT_LOAD_NO_AUTOHINT;
+ if (UserFlags & ImGuiFreeType::ForceAutoHint)
+ LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
+ if (UserFlags & ImGuiFreeType::LightHinting)
+ LoadFlags |= FT_LOAD_TARGET_LIGHT;
+ else if (UserFlags & ImGuiFreeType::MonoHinting)
+ LoadFlags |= FT_LOAD_TARGET_MONO;
+ else
+ LoadFlags |= FT_LOAD_TARGET_NORMAL;
return true;
}
- void FreeTypeFont::Shutdown()
+ void FreeTypeFont::CloseFont()
{
- if (FreetypeFace)
+ if (Face)
{
- FT_Done_Face(FreetypeFace);
- FreetypeFace = NULL;
- FT_Done_FreeType(FreetypeLibrary);
- FreetypeLibrary = NULL;
+ FT_Done_Face(Face);
+ Face = NULL;
}
}
- void FreeTypeFont::SetPixelHeight(int pixel_height)
+ void FreeTypeFont::SetPixelHeight(int pixel_height)
{
- // I'm not sure how to deal with font sizes properly.
- // As far as I understand, currently ImGui assumes that the 'pixel_height' is a maximum height of an any given glyph,
- // i.e. it's the sum of font's ascender and descender. Seems strange to me.
+ // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
+ // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
+ // NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result.
FT_Size_RequestRec req;
req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
req.width = 0;
req.height = (uint32_t)pixel_height * 64;
req.horiResolution = 0;
req.vertResolution = 0;
- FT_Request_Size(FreetypeFace, &req);
+ FT_Request_Size(Face, &req);
- // update font info
- FT_Size_Metrics metrics = FreetypeFace->size->metrics;
+ // Update font info
+ FT_Size_Metrics metrics = Face->size->metrics;
Info.PixelHeight = (uint32_t)pixel_height;
Info.Ascender = (float)FT_CEIL(metrics.ascender);
Info.Descender = (float)FT_CEIL(metrics.descender);
@@ -180,52 +177,58 @@ namespace
Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance);
}
- bool FreeTypeFont::CalcGlyphInfo(uint32_t codepoint, GlyphInfo &glyph_info, FT_Glyph& ft_glyph, FT_BitmapGlyph& ft_bitmap)
+ const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
{
- uint32_t glyph_index = FT_Get_Char_Index(FreetypeFace, codepoint);
+ uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
if (glyph_index == 0)
- return false;
- FT_Error error = FT_Load_Glyph(FreetypeFace, glyph_index, FreetypeLoadFlags);
+ return NULL;
+ FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
if (error)
- return false;
+ return NULL;
// Need an outline for this to work
- FT_GlyphSlot slot = FreetypeFace->glyph;
+ FT_GlyphSlot slot = Face->glyph;
IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE);
+ // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting)
if (UserFlags & ImGuiFreeType::Bold)
FT_GlyphSlot_Embolden(slot);
if (UserFlags & ImGuiFreeType::Oblique)
+ {
FT_GlyphSlot_Oblique(slot);
+ //FT_BBox bbox;
+ //FT_Outline_Get_BBox(&slot->outline, &bbox);
+ //slot->metrics.width = bbox.xMax - bbox.xMin;
+ //slot->metrics.height = bbox.yMax - bbox.yMin;
+ }
- // Retrieve the glyph
- error = FT_Get_Glyph(slot, &ft_glyph);
- if (error != 0)
- return false;
+ return &slot->metrics;
+ }
- // Rasterize
- error = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, NULL, true);
+ const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
+ {
+ FT_GlyphSlot slot = Face->glyph;
+ FT_Error error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
if (error != 0)
- return false;
+ return NULL;
- ft_bitmap = (FT_BitmapGlyph)ft_glyph;
- glyph_info.AdvanceX = (float)FT_CEIL(slot->advance.x);
- glyph_info.OffsetX = (float)ft_bitmap->left;
- glyph_info.OffsetY = -(float)ft_bitmap->top;
- glyph_info.Width = (float)ft_bitmap->bitmap.width;
- glyph_info.Height = (float)ft_bitmap->bitmap.rows;
+ FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
+ out_glyph_info->Width = (int)ft_bitmap->width;
+ out_glyph_info->Height = (int)ft_bitmap->rows;
+ out_glyph_info->OffsetX = Face->glyph->bitmap_left;
+ out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
+ out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x);
- return true;
+ return ft_bitmap;
}
- void FreeTypeFont::BlitGlyph(FT_BitmapGlyph ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
+ void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
{
IM_ASSERT(ft_bitmap != NULL);
-
- const uint32_t w = ft_bitmap->bitmap.width;
- const uint32_t h = ft_bitmap->bitmap.rows;
- const uint8_t* src = ft_bitmap->bitmap.buffer;
- const uint32_t src_pitch = ft_bitmap->bitmap.pitch;
+ const uint32_t w = ft_bitmap->width;
+ const uint32_t h = ft_bitmap->rows;
+ const uint8_t* src = ft_bitmap->buffer;
+ const uint32_t src_pitch = ft_bitmap->pitch;
if (multiply_table == NULL)
{
@@ -241,148 +244,399 @@ namespace
}
}
+#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
#define STBRP_ASSERT(x) IM_ASSERT(x)
#define STBRP_STATIC
#define STB_RECT_PACK_IMPLEMENTATION
#include "imstb_rectpack.h"
+#endif
-bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
+struct ImFontBuildSrcGlyphFT
+{
+ GlyphInfo Info;
+ uint32_t Codepoint;
+ unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
+};
+
+struct ImFontBuildSrcDataFT
+{
+ FreeTypeFont Font;
+ stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
+ const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
+ int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
+ int GlyphsHighest; // Highest requested codepoint
+ int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
+ ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
+ ImVector GlyphsList;
+};
+
+// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
+struct ImFontBuildDstDataFT
+{
+ int SrcCount; // Number of source fonts targeting this destination font.
+ int GlyphsHighest;
+ int GlyphsCount;
+ ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
+};
+
+bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
{
IM_ASSERT(atlas->ConfigData.Size > 0);
- IM_ASSERT(atlas->TexGlyphPadding == 1); // Not supported
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
- atlas->TexID = NULL;
+ // Clear atlas
+ atlas->TexID = (ImTextureID)NULL;
atlas->TexWidth = atlas->TexHeight = 0;
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
atlas->ClearTexData();
- ImVector fonts;
- fonts.resize(atlas->ConfigData.Size);
-
- ImVec2 max_glyph_size(1.0f, 1.0f);
+ // Temporary storage for building
+ ImVector src_tmp_array;
+ ImVector dst_tmp_array;
+ src_tmp_array.resize(atlas->ConfigData.Size);
+ dst_tmp_array.resize(atlas->Fonts.Size);
+ memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
+ memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
- // Count glyphs/ranges, initialize font
- int total_glyphs_count = 0;
- int total_ranges_count = 0;
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
+ // 1. Initialize font loading structure, check font data validity
+ for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
{
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- FreeTypeFont& font_face = fonts[input_i];
+ ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ FreeTypeFont& font_face = src_tmp.Font;
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
- if (!font_face.Init(cfg, extra_flags))
+ // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
+ src_tmp.DstIndex = -1;
+ for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
+ if (cfg.DstFont == atlas->Fonts[output_i])
+ src_tmp.DstIndex = output_i;
+ IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
+ if (src_tmp.DstIndex == -1)
+ return false;
+
+ // Load font
+ if (!font_face.InitFont(ft_library, cfg, extra_flags))
return false;
- max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth);
- max_glyph_size.y = ImMax(max_glyph_size.y, font_face.Info.Ascender - font_face.Info.Descender);
+ // Measure highest codepoints
+ ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
+ src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
+ for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
+ src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
+ dst_tmp.SrcCount++;
+ dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
+ }
+
+ // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
+ int total_glyphs_count = 0;
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
+ ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
+ if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
+ dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
+
+ for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
+ for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
+ {
+ if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
+ continue;
+ uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
+ if (glyph_index == 0)
+ continue;
+
+ // Add to avail set/counters
+ src_tmp.GlyphsCount++;
+ dst_tmp.GlyphsCount++;
+ src_tmp.GlyphsSet.SetBit(codepoint, true);
+ if (dst_tmp.SrcCount > 1)
+ dst_tmp.GlyphsSet.SetBit(codepoint, true);
+ total_glyphs_count++;
+ }
+ }
+
+ // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
+ src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
+
+ IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(int));
+ const int* it_begin = src_tmp.GlyphsSet.Storage.begin();
+ const int* it_end = src_tmp.GlyphsSet.Storage.end();
+ for (const int* it = it_begin; it < it_end; it++)
+ if (int entries_32 = *it)
+ for (int bit_n = 0; bit_n < 32; bit_n++)
+ if (entries_32 & (1 << bit_n))
+ {
+ ImFontBuildSrcGlyphFT src_glyph;
+ memset(&src_glyph, 0, sizeof(src_glyph));
+ src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
+ //src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
+ src_tmp.GlyphsList.push_back(src_glyph);
+ }
+ src_tmp.GlyphsSet.Clear();
+ IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
+ }
+ for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
+ dst_tmp_array[dst_i].GlyphsSet.Clear();
+ dst_tmp_array.clear();
+
+ // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
+ // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
+ ImVector buf_rects;
+ buf_rects.resize(total_glyphs_count);
+ memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
+
+ // Allocate temporary rasterization data buffers.
+ // We could not find a way to retrieve accurate glyph size without rendering them.
+ // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
+ // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't find the temporary allocations.
+ const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
+ int buf_bitmap_current_used_bytes = 0;
+ ImVector buf_bitmap_buffers;
+ buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
+
+ // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
+ // 8. Render/rasterize font characters into the texture
+ int total_surface = 0;
+ int buf_rects_out_n = 0;
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
+
+ src_tmp.Rects = &buf_rects[buf_rects_out_n];
+ buf_rects_out_n += src_tmp.GlyphsCount;
+
+ // Compute multiply table if requested
+ const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
+ unsigned char multiply_table[256];
+ if (multiply_enabled)
+ ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
+
+ // Gather the sizes of all rectangles we will need to pack
+ const int padding = atlas->TexGlyphPadding;
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
+ {
+ ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
+
+ const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
+ IM_ASSERT(metrics != NULL);
+ if (metrics == NULL)
+ continue;
+
+ // Render glyph into a bitmap (currently held by FreeType)
+ const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
+ IM_ASSERT(ft_bitmap);
+
+ // Allocate new temporary chunk if needed
+ const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height;
+ if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
+ {
+ buf_bitmap_current_used_bytes = 0;
+ buf_bitmap_buffers.push_back((unsigned char*)ImGui::MemAlloc(BITMAP_BUFFERS_CHUNK_SIZE));
+ }
+
+ // Blit rasterized pixels to our temporary buffer and keep a pointer to it.
+ src_glyph.BitmapData = buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes;
+ buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
+ src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width * 1, multiply_enabled ? multiply_table : NULL);
- if (!cfg.GlyphRanges)
- cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
- for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[ 1 ]; in_range += 2, total_ranges_count++)
- total_glyphs_count += (in_range[1] - in_range[0]) + 1;
+ src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding);
+ src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding);
+ total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
+ }
}
- // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
- // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
- atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
+ // We need a width for the skyline algorithm, any width!
+ // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
+ // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
+ const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
+ atlas->TexHeight = 0;
+ if (atlas->TexDesiredWidth > 0)
+ atlas->TexWidth = atlas->TexDesiredWidth;
+ else
+ atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
+
+ // 5. Start packing
+ // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
+ const int TEX_HEIGHT_MAX = 1024 * 32;
+ const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
+ ImVector pack_nodes;
+ pack_nodes.resize(num_nodes_for_packing_algorithm);
+ stbrp_context pack_context;
+ stbrp_init_target(&pack_context, atlas->TexWidth, TEX_HEIGHT_MAX, pack_nodes.Data, pack_nodes.Size);
+ ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
- // We don't do the original first pass to determine texture height, but just rough estimate.
- // Looks ugly inaccurate and excessive, but AFAIK with FreeType we actually need to render glyphs to get exact sizes.
- // Alternatively, we could just render all glyphs into a big shadow buffer, get their sizes, do the rectangle packing and just copy back from the
- // shadow buffer to the texture buffer. Will give us an accurate texture height, but eat a lot of temp memory. Probably no one will notice.)
- const int total_rects = total_glyphs_count + atlas->CustomRects.size();
- float min_rects_per_row = ceilf((atlas->TexWidth / (max_glyph_size.x + 1.0f)));
- float min_rects_per_column = ceilf(total_rects / min_rects_per_row);
- atlas->TexHeight = (int)(min_rects_per_column * (max_glyph_size.y + 1.0f));
+ // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
+
+ stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount);
- // Create texture
+ // Extend texture height and mark missing glyphs as non-packed so we won't render them.
+ // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
+ if (src_tmp.Rects[glyph_i].was_packed)
+ atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
+ }
+
+ // 7. Allocate texture
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
- // Start packing
- ImVector pack_nodes;
- pack_nodes.resize(total_rects);
- stbrp_context context;
- stbrp_init_target(&context, atlas->TexWidth, atlas->TexHeight, pack_nodes.Data, total_rects);
+ // 8. Copy rasterized font characters back into the main texture
+ // 9. Setup ImFont and glyphs for runtime
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ {
+ ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
+ if (src_tmp.GlyphsCount == 0)
+ continue;
- // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
- ImFontAtlasBuildPackCustomRects(atlas, &context);
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
+ ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
- // Render characters, setup ImFont and glyphs for runtime
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
- {
- ImFontConfig& cfg = atlas->ConfigData[input_i];
- FreeTypeFont& font_face = fonts[input_i];
- ImFont* dst_font = cfg.DstFont;
- if (cfg.MergeMode)
- dst_font->BuildLookupTable();
-
- const float ascent = font_face.Info.Ascender;
- const float descent = font_face.Info.Descender;
+ const float ascent = src_tmp.Font.Info.Ascender;
+ const float descent = src_tmp.Font.Info.Descender;
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
const float font_off_x = cfg.GlyphOffset.x;
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
- bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f);
- unsigned char multiply_table[256];
- if (multiply_enabled)
- ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
-
- for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
+ const int padding = atlas->TexGlyphPadding;
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
{
- for (uint32_t codepoint = in_range[0]; codepoint <= in_range[1]; ++codepoint)
- {
- if (cfg.MergeMode && dst_font->FindGlyphNoFallback((ImWchar)codepoint))
- continue;
-
- FT_Glyph ft_glyph = NULL;
- FT_BitmapGlyph ft_glyph_bitmap = NULL; // NB: will point to bitmap within FT_Glyph
- GlyphInfo glyph_info;
- if (!font_face.CalcGlyphInfo(codepoint, glyph_info, ft_glyph, ft_glyph_bitmap))
- continue;
-
- // Pack rectangle
- stbrp_rect rect;
- rect.w = (uint16_t)glyph_info.Width + 1; // Account for texture filtering
- rect.h = (uint16_t)glyph_info.Height + 1;
- stbrp_pack_rects(&context, &rect, 1);
-
- // Copy rasterized pixels to main texture
- uint8_t* blit_dst = atlas->TexPixelsAlpha8 + rect.y * atlas->TexWidth + rect.x;
- font_face.BlitGlyph(ft_glyph_bitmap, blit_dst, atlas->TexWidth, multiply_enabled ? multiply_table : NULL);
- FT_Done_Glyph(ft_glyph);
-
- float char_advance_x_org = glyph_info.AdvanceX;
- float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
- float char_off_x = font_off_x;
- if (char_advance_x_org != char_advance_x_mod)
- char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
-
- // Register glyph
- dst_font->AddGlyph((ImWchar)codepoint,
- glyph_info.OffsetX + char_off_x,
- glyph_info.OffsetY + font_off_y,
- glyph_info.OffsetX + char_off_x + glyph_info.Width,
- glyph_info.OffsetY + font_off_y + glyph_info.Height,
- rect.x / (float)atlas->TexWidth,
- rect.y / (float)atlas->TexHeight,
- (rect.x + glyph_info.Width) / (float)atlas->TexWidth,
- (rect.y + glyph_info.Height) / (float)atlas->TexHeight,
- char_advance_x_mod);
- }
+ ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
+ stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
+ IM_ASSERT(pack_rect.was_packed);
+
+ GlyphInfo& info = src_glyph.Info;
+ IM_ASSERT(info.Width + padding <= pack_rect.w);
+ IM_ASSERT(info.Height + padding <= pack_rect.h);
+ const int tx = pack_rect.x + padding;
+ const int ty = pack_rect.y + padding;
+
+ // Blit from temporary buffer to final texture
+ size_t blit_src_stride = (size_t)src_glyph.Info.Width;
+ size_t blit_dst_stride = (size_t)atlas->TexWidth;
+ unsigned char* blit_src = src_glyph.BitmapData;
+ unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
+ for (int y = info.Height; y > 0; y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
+ memcpy(blit_dst, blit_src, blit_src_stride);
+
+ float char_advance_x_org = info.AdvanceX;
+ float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
+ float char_off_x = font_off_x;
+ if (char_advance_x_org != char_advance_x_mod)
+ char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
+
+ // Register glyph
+ float x0 = info.OffsetX + char_off_x;
+ float y0 = info.OffsetY + font_off_y;
+ float x1 = x0 + info.Width;
+ float y1 = y0 + info.Height;
+ float u0 = (tx) / (float)atlas->TexWidth;
+ float v0 = (ty) / (float)atlas->TexHeight;
+ float u1 = (tx + info.Width) / (float)atlas->TexWidth;
+ float v1 = (ty + info.Height) / (float)atlas->TexHeight;
+ dst_font->AddGlyph((ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, char_advance_x_mod);
}
+
+ src_tmp.Rects = NULL;
}
// Cleanup
- for (int n = 0; n < fonts.Size; n++)
- fonts[n].Shutdown();
+ for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
+ ImGui::MemFree(buf_bitmap_buffers[buf_i]);
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
+ src_tmp_array[src_i].~ImFontBuildSrcDataFT();
ImFontAtlasBuildFinish(atlas);
return true;
}
+
+// Default memory allocators
+static void* ImFreeTypeDefaultAllocFunc(size_t size, void* user_data) { IM_UNUSED(user_data); return ImGui::MemAlloc(size); }
+static void ImFreeTypeDefaultFreeFunc(void* ptr, void* user_data) { IM_UNUSED(user_data); ImGui::MemFree(ptr); }
+
+// Current memory allocators
+static void* (*GImFreeTypeAllocFunc)(size_t size, void* user_data) = ImFreeTypeDefaultAllocFunc;
+static void (*GImFreeTypeFreeFunc)(void* ptr, void* user_data) = ImFreeTypeDefaultFreeFunc;
+static void* GImFreeTypeAllocatorUserData = NULL;
+
+// FreeType memory allocation callbacks
+static void* FreeType_Alloc(FT_Memory /*memory*/, long size)
+{
+ return GImFreeTypeAllocFunc((size_t)size, GImFreeTypeAllocatorUserData);
+}
+
+static void FreeType_Free(FT_Memory /*memory*/, void* block)
+{
+ GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData);
+}
+
+static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size, void* block)
+{
+ // Implement realloc() as we don't ask user to provide it.
+ if (block == NULL)
+ return GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData);
+
+ if (new_size == 0)
+ {
+ GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData);
+ return NULL;
+ }
+
+ if (new_size > cur_size)
+ {
+ void* new_block = GImFreeTypeAllocFunc((size_t)new_size, GImFreeTypeAllocatorUserData);
+ memcpy(new_block, block, (size_t)cur_size);
+ GImFreeTypeFreeFunc(block, GImFreeTypeAllocatorUserData);
+ return new_block;
+ }
+
+ return block;
+}
+
+bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags)
+{
+ // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html
+ FT_MemoryRec_ memory_rec = { 0 };
+ memory_rec.alloc = &FreeType_Alloc;
+ memory_rec.free = &FreeType_Free;
+ memory_rec.realloc = &FreeType_Realloc;
+
+ // https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library
+ FT_Library ft_library;
+ FT_Error error = FT_New_Library(&memory_rec, &ft_library);
+ if (error != 0)
+ return false;
+
+ // If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
+ FT_Add_Default_Modules(ft_library);
+
+ bool ret = ImFontAtlasBuildWithFreeType(ft_library, atlas, extra_flags);
+ FT_Done_Library(ft_library);
+
+ return ret;
+}
+
+void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
+{
+ GImFreeTypeAllocFunc = alloc_func;
+ GImFreeTypeFreeFunc = free_func;
+ GImFreeTypeAllocatorUserData = user_data;
+}
diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h
index b8062bf7..9df5780e 100644
--- a/misc/freetype/imgui_freetype.h
+++ b/misc/freetype/imgui_freetype.h
@@ -1,4 +1,4 @@
-// Wrapper to use Freetype (instead of stb_truetype) for Dear ImGui
+// Wrapper to use FreeType (instead of stb_truetype) for Dear ImGui
// Get latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype
// Original code by @Vuhdo (Aleksei Skriabin), maintained by @ocornut
@@ -12,10 +12,10 @@ namespace ImGuiFreeType
// When disabled, FreeType generates blurrier glyphs, more or less matches the stb's output.
// The Default hinting mode usually looks good, but may distort glyphs in an unusual way.
// The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer.
-
+
// You can set those flags on a per font basis in ImFontConfig::RasterizerFlags.
// Use the 'extra_flags' parameter of BuildFontAtlas() to force a flag on all your fonts.
- enum RasterizerFlags
+ enum RasterizerFlags
{
// By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter.
NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes.
@@ -28,4 +28,8 @@ namespace ImGuiFreeType
};
IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0);
+
+ // By default ImGuiFreeType will use ImGui::MemAlloc()/MemFree().
+ // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired:
+ IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);
}
diff --git a/misc/natvis/README.txt b/misc/natvis/README.txt
index 60073874..1219db45 100644
--- a/misc/natvis/README.txt
+++ b/misc/natvis/README.txt
@@ -1,4 +1,4 @@
-Natvis file to describe dear imgui types in the Visual Studio debugger.
-With this, types like ImVector<> will be displayed nicely in the debugger.
+Natvis file to describe dear imgui types in the Visual Studio debugger.
+With this, types like ImVector<> will be displayed nicely in the debugger.
You can include this file a Visual Studio project file, or install it in Visual Studio folder.
diff --git a/misc/natvis/imgui.natvis b/misc/natvis/imgui.natvis
index 48b20426..cc768bfb 100644
--- a/misc/natvis/imgui.natvis
+++ b/misc/natvis/imgui.natvis
@@ -33,7 +33,7 @@
- {{Name={Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d}}
+ {{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}}
\ No newline at end of file