3rdparty: Update ImGui to v1.92.7

This commit is contained in:
JordanTheToaster
2026-04-05 14:37:02 +01:00
committed by lightningterror
parent a6d4a67581
commit 603687389f
12 changed files with 1204 additions and 645 deletions
+165
View File
@@ -39,6 +39,171 @@ HOW TO UPDATE?
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!
-----------------------------------------------------------------------
VERSION 1.92.7 (Released 2026-04-02)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.7
Breaking Changes:
- Separator: fixed a legacy quirk where `Separator()` was submitting a zero-height
item for layout purpose, even though it draws a 1-pixel separator.
The fix could affect code e.g. computing height from multiple widgets in order to
allocate vertical space for a footer or multi-line status bar. (#2657, #9263)
The "Console" example had such a bug:
float footer_height = style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
BeginChild("ScrollingRegion", { 0, -footer_height });
Should be:
float footer_height = style.ItemSpacing.y + style.SeparatorSize + ImGui::GetFrameHeightWithSpacing();
BeginChild("ScrollingRegion", { 0, -footer_height });
When such idiom was used and assuming zero-height Separator, it is likely that
in 1.92.7 the resulting window will have unexpected 1 pixel scrolling range.
- Multi-Select: renamed `ImGuiMultiSelectFlags_SelectOnClick` to `ImGuiMultiSelectFlags_SelectOnAuto`.
Kept inline redirection enum (will obsolete).
- Combo(), ListBox(): commented out legacy signatures which were obsoleted in 1.90
(Nov 2023), when the getter callback type was changed from:
bool (*getter)(void* user_data, int idx, const char** out_text)
To:
const char* (*getter)(void* user_data, int idx)
Other Changes:
- TreeNode:
- Moved `TreeNodeGetOpen()` helper to public API. I was hesitant to make this public
because I intend to provide a more generic and feature-full version, but in the meanwhile
this will do. (#3823, #9251, #7553, #6754, #5423, #2958, #2079, #1947, #1131, #722)
- In 'Demo->Property Editor' demonstrate a way to perform tree clipping by fast-forwarding
through non-visible chunks. (#3823, #9251, #6990, #6042)
Using SetNextItemStorageID() + TreeNodeGetOpen() makes this notably easier than
it was prior to 1.91.
- InputText:
- Shift+Enter in multi-line editor always adds a new line, regardless of
`ImGuiInputTextFlags_CtrlEnterForNewLine` being set or not. (#9239)
- Reworked `io.ConfigInputTextEnterKeepActive` mode so that pressing Enter will
deactivate/reactivate the item in order for e.g. `IsItemDeactivatedAfterEdit()`
signals to be emitted the same way regardless of that setting. (#9001, #9115)
- Fixed a glitch when using `ImGuiInputTextFlags_ElideLeft` where the local x offset
would be incorrect during the deactivation frame. (#9298)
- Fixed a crash introduced in 1.92.6 when handling `ImGuiInputTextFlags_CallbackResize`
in certain situations. (#9174)
- Fixed selection highlight Y1 offset being very slightly off (since 1.92.3). (#9311) [@v-ein]
- InputTextMultiline: fixed an issue introduced in 1.92.3 where line count calculated
for vertical scrollbar range would be +1 when the widget is inactive, word-wrap is
disabled and the text buffer ends with '\n'. Fixed a similar issue related to clipping
large amount of text.
- InputTextMultiline: avoid going through reactivation code and fixed losing revert value
when activating scrollbar.
- InputTextMultiline: fixed an issue where edit buffer wouldn't be reapplied to back
buffer on the `IsItemDeactivatedAfterEdit()` frame. This could create issues when
using the idiom of not applying edits before `IsItemDeactivatedAfterEdit()`.
(#9308, #8915, #8273)
- Tables:
- Allow reordering columns by dragging them in the context menu. (#9312)
- Context menu now presents columns in display order. (#9312)
- Fixed and clarified the behavior of using `TableSetupScrollFreeze()` with columns>1,
and where some of the columns within that range were Hidable.
- Before: `TableSetupScrollFreeze(N, 0)`: include the N left-most visible columns as
part of the scroll freeze. So if you intentionally hide columns <N, the scroll
freeze area would start covering the subsequent/following columns (N+1) etc.
- After: `TableSetupScrollFreeze(N, 0)`: include the N left-most columns (regardless of visibility),
as part of the scroll freeze. So if you intentionally hide columns <N, the scroll
freeze area will cover less columns.
- This is generally more sane and logical.
- Fixed dragging a header to reorder outside of visible bounds (due to horizontal scrolling)
from losing active id.
- Angled Headers: angled section for column being reordered via the regular headers
stays highlighted during reordering.
- Style:
- Fonts: fixed an issue introduced in 1.92.6 where `style.FontBaseSize` would be
cleared during the first frame if no fonts was explicitly added before.
- Border sizes are now scaled (and rounded) by `ScaleAllSizes()`.
- When using large values with `ScallAllSizes()`, the following items thickness
are scaled to integer amounts:
- `InputText()` caret/cursor thickness. (#7031)
- `CloseButton()` thickness.
- `TextLink()` underline thickness.
- `ColorButton()` border thickness.
- `Separator()` thickness, via scaling newly added `style.SeparatorSize`. (#2657, #9263)
- Nav:
- Popups: Shift+F10 or Menu key can now open popups menus when using
`BeginPopupContextItem()`, `BeginPopupContextWindow()` or `OpenPopupOnItemClick()`.
(#8803, #9270) [@exelix11, @ocornut]
- Changed Gamepad mapping for "Activate with Text Input" action: (#8803, #787)
- Previously: press North button (PS4/PS5 triangle, Switch X, Xbox Y).
- Now: long press (hold) Activate button (PS4/PS5 cross, Switch B, Xbox A) for ~0.60 secs.
This is rarely used, somehow easier to discover, and frees a button for other uses.
See updated Gamepad Control Sheets: https://www.dearimgui.com/controls_sheets
- Short Gamepad Activation press on InputText() always activate with Text Input mode.
- Popups: pressing North button (PS4/PS5 triangle, SwitchX, Xbox Y) also open popups menus.
- Multi-Select:
- Added `ImGuiMultiSelectFlags_SelectOnClickAlways` mode (rarely used).
This prevents Drag and Drop of multiple items, but it allows to start a new Box-Selection
from inside an existing selection (Excel style). (#9307, #1861)
- Clipper:
- Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false.
- Added `UserIndex` helper storage. This is solely a convenience for cases where
you may want to carry an index around.
- Always pulls current context on `ImGuiListClipper::Begin()`, consistent with public
API design, and avoids issues with clipper instances outliving contexts. (#9324, #5856)
- Scrollbar:
- Implemented a custom tweak to extend hit-testing bounding box when window is sitting
at the edge of a viewport (e.g. fullscreen or docked window), so that e.g. mouse the
mouse at the extreme of the screen will reach the scrollbar. (#9276)
- Fixed an issue which could lead initial click to move the current scroll by a pixel.
- Button:
- Moved `ImGuiButtonFlags_AllowOverlap` from imgui_internal.h to imgui.h,
as a convenience for when using e.g. `InvisibleButton()`.
- Focus: fixed fallback "Debug" window temporarily taking focus and setting `io.WantCaptureKeyboard`
for one frame on e.g. application boot if no other windows are submitted. (#9243)
- DrawList:
- PathArcTo(): fixed erroneous segment count for pathologically small arcs on large
circles. (#9331, #9313) [@thedmd, @epajarre]
- Memory:
- Discard/GC of ImDrawList buffers for unused windows favor restoring them to
~Size*1.05 instead of Capacity when awakening again. Facilitate releasing ImDrawList
buffers after unusual usage spike. (#9303)
- Fixed `GetForegroundDrawList()`/`GetBackgroundDrawList()` per-viewport buffers not being
collected when unused for `io.ConfigMemoryCompactTimer` amount of time. (#9303)
- Demo: fixed `IMGUI_DEMO_MARKER` locations for examples applets. (#9261, #3689) [@pthom]
- Misc: added missing ImVec2/ImVec4 operators. (#9339, #8258) [@dkosmari, @ArashPartow]
- Internals:
- ButtonBehavior: fixed internal/low-level `ImGuiButtonFlags_PressedOnRelease`
(as well as equivalent `ImGuiSelectableFlags_SelectOnRelease` for Selectable) from
not taking current active id. `ImGuiButtonFlags_NoHoldingActiveID` allows that.
This was only used internally by MenuItem().
- Backends:
- DirectX9, OpenGL2, OpenGL3, Metal, SDLGPU3, SDLRenderer2, SDLRenderer3: fixed easy-to-fix
issues in code assuming ImTextureID_Invalid is always defined to 0. (#9295, #9310)
- GLFW: mouse cursor is properly restored if changed by user app/code while using
`glfwSetInputMode(..., GLFW_CURSOR_DISABLED)` or `ImGuiConfigFlags_NoMouseCursorChange`.
Amend optimization done in 1.92.6.
- SDLGPU3: removed unnecessary call to `SDL_WaitForGPUIdle()` when releasing
vertex/index buffers. (#9262) [@jaenis]
- WebGPU: fixed version check for Emscripten 5.0.0+.
- WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante]
- WebGPU: added support for WGVK native backend via `IMGUI_IMPL_WEBGPU_BACKEND_WGVK`,
using SPIRV shaders if WGSL is not available. (#9316, #9246, #9257) [@r-lyeh]
(WGVK is a lightweight alternative to Dawn or WGPU for native applications,
which is easier to build/setup, see: https://github.com/manuel5975p/WGVK)
- Examples:
- Emscripten: added `tabindex=-1` to canvas in our shell_minimal.htm. Without it,
the canvas was not focusable in the DOM, which in turn make some backends
(e.g. pongasoft/emscripten-glfw) not receive focus loss events. (#9259) [@pthom]
- Emscripten: fixed minor rendering issues with our HTML shell. (#9281) [@ypujante]
- hidden small blue outline when canvas is focused on Chrome.
- hidden scrollbar in Firefox.
- Vulkan: added `ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[]` to allow specifying
extra dynamic states to add when creating the VkPipeline. (#9211) [@DziubanMaciej]
- Vulkan: `ImGui_ImplVulkan_AddTexture()` skips updating descriptor_set if failing
to allocate one. (#8677) [@micb25]
- WebGPU: fixed undefined behaviors in example code for requesting adapter
and device. (#9246, #9256) [@r-lyeh]
- SDL2+WebGPU: fixed hi-dpi handling. (#9300) [@ypujante]
- GLFW/SDL2/SDL3+WebGPU: added support for WGVK. (#9316, #9246, #9257) [@r-lyeh, @ocornut]
- GLFW/SDL2/SDL3+WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante]
-----------------------------------------------------------------------
VERSION 1.92.6 (2026-02-17)
-----------------------------------------------------------------------
+57 -33
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.6
// dear imgui, v1.92.7
// (headers)
// Help:
@@ -20,7 +20,7 @@
// - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui
// - Issues & support ........... https://github.com/ocornut/imgui/issues
// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps)
// - Web version of the Demo .... https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html (w/ source code browser)
// - Web version of the Demo .... https://pthom.github.io/imgui_explorer (w/ source code browser)
// For FIRST-TIME users having issues compiling/linking/running:
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
@@ -29,8 +29,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.6"
#define IMGUI_VERSION_NUM 19261
#define IMGUI_VERSION "1.92.7"
#define IMGUI_VERSION_NUM 19270
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
@@ -340,7 +340,9 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE
typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that.
#endif
// Define this if you need 0 to be a valid ImTextureID for your backend.
// Define this if you need to change the invalid value for your backend.
// - If your backend is using ImTextureID to store an index/offset and you need 0 to be valid, You can add '#define ImTextureID_Invalid ((ImTextureID)-1)' in your imconfig.h file.
// - From 2026/03/12 to 2026/03/19 we experimented with changing to default to -1, but I worried it would cause too many issues in third-party code so it was reverted.
#ifndef ImTextureID_Invalid
#define ImTextureID_Invalid ((ImTextureID)0)
#endif
@@ -756,6 +758,7 @@ namespace ImGui
IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header.
IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
IMGUI_API void SetNextItemStorageID(ImGuiID storage_id); // set id to use for open/close storage (default to same as item id).
IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); // retrieve tree node open/close state.
// Widgets: Selectables
// - A selectable highlights when hovered, and can display another color when selected.
@@ -911,7 +914,7 @@ namespace ImGui
// The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody.
// - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in
// some advanced use cases (e.g. adding custom widgets in header row).
// - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled.
// - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. When freezing columns you would usually also use ImGuiTableColumnFlags_NoHide on them.
IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0);
IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled.
IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used)
@@ -998,7 +1001,7 @@ namespace ImGui
IMGUI_API void SetNavCursorVisible(bool visible); // alter visibility of keyboard/gamepad cursor. by default: show when using an arrow key, hide when clicking with mouse.
// Overlapping mode
IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this.
IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Typically useful with InvisibleButton(), Selectable(), TreeNode() covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this.
// Item/Widgets Utilities and Query Functions
// - Most of the functions are referring to the previous Item that has been submitted.
@@ -1258,7 +1261,7 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field
ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider using IsItemDeactivatedAfterEdit() instead!
ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert)
ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter).
ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode: validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter). Note that Shift+Enter always enter a new line either way.
// Other options
ImGuiInputTextFlags_ReadOnly = 1 << 9, // Read-only mode
@@ -1300,13 +1303,13 @@ enum ImGuiTreeNodeFlags_
ImGuiTreeNodeFlags_None = 0,
ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected
ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader)
ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one
ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing will allow subsequent widgets to overlap this one. Require previous frame HoveredId to match before being usable. Shortcut to calling SetNextItemAllowOverlap().
ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack
ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes)
ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open
ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Open on double-click instead of simple click (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined.
ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Open when clicking on the arrow part (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined.
ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes).
ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). Note: will always open a tree/id scope and return true. If you never use that scope, add ImGuiTreeNodeFlags_NoTreePushOnOpen.
ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag!
ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node.
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode.
@@ -1360,7 +1363,7 @@ enum ImGuiSelectableFlags_
ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Frame will span all columns of its container table (text will still fit in current column)
ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too
ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // Hit testing will allow subsequent widgets to overlap this one. Require previous frame HoveredId to match before being usable. Shortcut to calling SetNextItemAllowOverlap().
ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered
ImGuiSelectableFlags_SelectOnNav = 1 << 6, // Auto-select when moved into, unless Ctrl is held. Automatic when in a BeginMultiSelect() block.
@@ -1615,10 +1618,10 @@ enum ImGuiKey : int
// // XBOX | SWITCH | PLAYSTA. | -> ACTION
ImGuiKey_GamepadStart, // Menu | + | Options |
ImGuiKey_GamepadBack, // View | - | Share |
ImGuiKey_GamepadFaceLeft, // X | Y | Square | Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows)
ImGuiKey_GamepadFaceLeft, // X | Y | Square | Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows)
ImGuiKey_GamepadFaceRight, // B | A | Circle | Cancel / Close / Exit
ImGuiKey_GamepadFaceUp, // Y | X | Triangle | Text Input / On-screen Keyboard
ImGuiKey_GamepadFaceDown, // A | B | Cross | Activate / Open / Toggle / Tweak
ImGuiKey_GamepadFaceUp, // Y | X | Triangle | Open Context Menu
ImGuiKey_GamepadFaceDown, // A | B | Cross | Activate / Open / Toggle. Hold for 0.60f to Activate in Text Input mode (e.g. wired to an on-screen keyboard).
ImGuiKey_GamepadDpadLeft, // D-pad Left | " | " | Move / Tweak / Resize Window (in Windowing mode)
ImGuiKey_GamepadDpadRight, // D-pad Right | " | " | Move / Tweak / Resize Window (in Windowing mode)
ImGuiKey_GamepadDpadUp, // D-pad Up | " | " | Move / Tweak / Resize Window (in Windowing mode)
@@ -1700,6 +1703,7 @@ enum ImGuiInputFlags_
};
// Configuration flags stored in io.ConfigFlags. Set by user/application.
// Note that nowadays most of our configuration options are in other ImGuiIO fields, e.g. io.ConfigWindowsMoveFromTitleBarOnly.
enum ImGuiConfigFlags_
{
ImGuiConfigFlags_None = 0,
@@ -1709,10 +1713,9 @@ enum ImGuiConfigFlags_
ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states.
// User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui)
// [Unused] User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui)
ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware.
ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos
ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard
@@ -1851,6 +1854,7 @@ enum ImGuiStyleVar_
ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
ImGuiStyleVar_SeparatorSize, // float SeparatorSize
ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize
ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign
ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding
@@ -1866,6 +1870,7 @@ enum ImGuiButtonFlags_
ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button
ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, // [Internal]
ImGuiButtonFlags_EnableNav = 1 << 3, // InvisibleButton(): do not disable navigation/tabbing. Otherwise disabled by default.
ImGuiButtonFlags_AllowOverlap = 1 << 12, // Hit testing will allow subsequent widgets to overlap this one. Require previous frame HoveredId to match before being usable. Shortcut to calling SetNextItemAllowOverlap().
};
// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton()
@@ -2025,11 +2030,11 @@ enum ImGuiTableFlags_
// Features
ImGuiTableFlags_None = 0,
ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns.
ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row. (Need calling TableSetupColumn() + TableHeadersRow() to display headers, or using ImGuiTableFlags_ContextMenuInBody to access context-menu without headers).
ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu.
ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate.
ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width, visibility and sort settings in the .ini file.
ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will also display table context menu. By default it is available in TableHeadersRow().
// Decorations
ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)
ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows.
@@ -2330,6 +2335,7 @@ struct ImGuiStyle
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
float SeparatorSize; // Thickness of border in Separator()
float SeparatorTextBorderSize; // Thickness of border in SeparatorText()
ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
@@ -2354,7 +2360,7 @@ struct ImGuiStyle
ImGuiHoveredFlags HoverFlagsForTooltipNav; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad.
// [Internal]
float _MainScale; // FIXME-WIP: Reference scale, as applied by ScaleAllSizes().
float _MainScale; // FIXME-WIP: Reference scale, as applied by ScaleAllSizes(). PLEASE DO NOT USE THIS FOR NOW.
float _NextFrameFontSizeBase; // FIXME: Temporary hack until we finish remaining work.
// Functions
@@ -2425,7 +2431,7 @@ struct ImGuiIO
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + 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.
bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.
bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting).
bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only).
bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only).
bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard.
bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar.
@@ -2850,15 +2856,16 @@ enum ImGuiListClipperFlags_
// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc.
struct ImGuiListClipper
{
ImGuiContext* Ctx; // Parent UI context
int DisplayStart; // First item to display, updated by each call to Step()
int DisplayEnd; // End of items to display (exclusive)
int UserIndex; // Helper storage for user convenience/code. Optional, and otherwise unused if you don't use it.
int ItemsCount; // [Internal] Number of items
float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it
ImGuiListClipperFlags Flags; // [Internal] Flags, currently not yet well exposed.
double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed
double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows.
ImGuiContext* Ctx; // [Internal] Parent UI context
void* TempData; // [Internal] Internal data
ImGuiListClipperFlags Flags; // [Internal] Flags, currently not yet well exposed.
// items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step, and you can call SeekCursorForItem() manually if you need)
// items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing().
@@ -2889,17 +2896,18 @@ struct ImGuiListClipper
// - It is important that we are keeping those disabled by default so they don't leak in user space.
// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h)
// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4.
// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface for possible user mistake.
#ifdef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED
IM_MSVC_RUNTIME_CHECKS_OFF
// ImVec2 operators
inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
inline ImVec2 operator*(const float lhs, const ImVec2& rhs) { return ImVec2(lhs * rhs.x, lhs * rhs.y); }
inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
inline ImVec2 operator+(const ImVec2& lhs) { return lhs; }
inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); }
inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
@@ -2911,12 +2919,20 @@ inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x =
inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; }
// ImVec4 operators
inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); }
inline ImVec4 operator*(const float lhs, const ImVec4& rhs) { return ImVec4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w); }
inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); }
inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); }
inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); }
inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); }
inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); }
inline ImVec4 operator+(const ImVec4& lhs) { return lhs; }
inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); }
inline ImVec4& operator*=(ImVec4& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; lhs.z *= rhs; lhs.w *= rhs; return lhs; }
inline ImVec4& operator/=(ImVec4& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; lhs.z /= rhs; lhs.w /= rhs; return lhs; }
inline ImVec4& operator+=(ImVec4& lhs, const ImVec4& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z; lhs.w += rhs.w; return lhs; }
inline ImVec4& operator-=(ImVec4& lhs, const ImVec4& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; lhs.z -= rhs.z; lhs.w -= rhs.w; return lhs; }
inline ImVec4& operator*=(ImVec4& lhs, const ImVec4& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; lhs.z *= rhs.z; lhs.w *= rhs.w; return lhs; }
inline ImVec4& operator/=(ImVec4& lhs, const ImVec4& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; lhs.z /= rhs.z; lhs.w /= rhs.w; return lhs; }
inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; }
inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; }
IM_MSVC_RUNTIME_CHECKS_RESTORE
@@ -3018,16 +3034,23 @@ enum ImGuiMultiSelectFlags_
ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item.
ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space.
ImGuiMultiSelectFlags_BoxSelect2d = 1 << 7, // Enable box-selection with varying width or varying x pos items support (e.g. different width labels, or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items.
ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting near edges of scope.
ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting and moving mouse near edges of scope.
ImGuiMultiSelectFlags_ClearOnEscape = 1 << 9, // Clear selection when pressing Escape while scope is focused.
ImGuiMultiSelectFlags_ClearOnClickVoid = 1 << 10, // Clear selection when clicking on empty location within scope.
ImGuiMultiSelectFlags_ScopeWindow = 1 << 11, // Scope for _BoxSelect and _ClearOnClickVoid is whole window (Default). Use if BeginMultiSelect() covers a whole window or used a single time in same window.
ImGuiMultiSelectFlags_ScopeRect = 1 << 12, // Scope for _BoxSelect and _ClearOnClickVoid is rectangle encompassing BeginMultiSelect()/EndMultiSelect(). Use if BeginMultiSelect() is called multiple times in same window.
ImGuiMultiSelectFlags_SelectOnClick = 1 << 13, // Apply selection on mouse down when clicking on unselected item. (Default)
ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 14, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection.
ImGuiMultiSelectFlags_SelectOnAuto = 1 << 13, // Apply selection on mouse down when clicking on unselected item, on mouse up when clicking on selected item. (Default)
ImGuiMultiSelectFlags_SelectOnClickAlways = 1 << 14, // Apply selection on mouse down when clicking on any items. Prevents Drag and Drop from being used on multiple-selection, but allows e.g. BoxSelect to always reselect even when clicking inside an existing selection. (Excel style behavior)
ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 15, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection.
//ImGuiMultiSelectFlags_RangeSelect2d = 1 << 15, // Shift+Selection uses 2d geometry instead of linear sequence, so possible to use Shift+up/down to select vertically in grid. Analogous to what BoxSelect does.
ImGuiMultiSelectFlags_NavWrapX = 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one.
ImGuiMultiSelectFlags_NoSelectOnRightClick = 1 << 17, // Disable default right-click processing, which selects item on mouse down, and is designed for context-menus.
ImGuiMultiSelectFlags_SelectOnMask_ = ImGuiMultiSelectFlags_SelectOnAuto | ImGuiMultiSelectFlags_SelectOnClickAlways | ImGuiMultiSelectFlags_SelectOnClickRelease,
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiMultiSelectFlags_SelectOnClick = ImGuiMultiSelectFlags_SelectOnAuto, // RENAMED in 1.92.6
#endif
};
// Main IO structure returned by BeginMultiSelect()/EndMultiSelect().
@@ -3641,7 +3664,7 @@ enum ImFontAtlasFlags_
// - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API.
// 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 persists 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,
@@ -3853,7 +3876,7 @@ struct ImFont
ImFontAtlas* OwnerAtlas; // 4-8 // What we have been loaded into.
ImFontFlags Flags; // 4 // Font flags.
float CurrentRasterizerDensity; // Current rasterizer density. This is a varying state of the font.
float LineHeight; // 4 // Line Height
float LineHeight; // 4 // Line Height
// [Internal] Members: Cold ~24-52 bytes
// Conceptually Sources[] is the list of font sources merged to create this font.
@@ -3904,8 +3927,10 @@ inline ImTextureID ImTextureRef::GetTexID() const
// Using an indirection to avoid patching ImDrawCmd after a SetTexID() call (but this could be an alternative solution too)
inline ImTextureID ImDrawCmd::GetTexID() const
{
// If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92)
// must iterate and handle ImTextureData requests stored in ImDrawData::Textures[].
// If you are getting this assert with ImTextureID_Invalid == 0 and your ImTextureID is used to store an index or an offset:
// - You can add '#define ImTextureID_Invalid ((ImTextureID)-1)' in your imconfig.h file.
// If you are getting this assert with a renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92+):
// - You must correctly iterate and handle ImTextureData requests stored in ImDrawData::Textures[]. See docs/BACKENDS.md.
ImTextureID tex_id = TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID; // == TexRef.GetTexID() above.
if (TexRef._TexData != NULL)
IM_ASSERT(tex_id != ImTextureID_Invalid && "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!");
@@ -4049,12 +4074,11 @@ namespace ImGui
IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
// OBSOLETED in 1.90.0 (from September 2023)
IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1);
IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1);
// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE)
// OBSOLETED in 1.90.0 (from September 2023)
//IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); // Getter signature changed. See 2023/09/15 and 2026/02/27 commits.
//IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); // Getter signature changed. See 2023/09/15 and 2026/02/27 commits.
//inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders
//inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders
//inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, flags); }
+33 -16
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.6
// dear imgui, v1.92.7
// (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -534,7 +534,7 @@ inline float ImLinearSweep(float current, float target, float speed) { if (cu
inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; }
inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / n; avg += sample / n; return avg; }
inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / (float)n; avg += sample / (float)n; return avg; }
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helpers: Geometry
@@ -1023,7 +1023,7 @@ enum ImGuiInputTextFlagsPrivate_
{
// [Internal]
ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline()
ImGuiInputTextFlags_MergedItem = 1 << 27, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match.
ImGuiInputTextFlags_TempInput = 1 << 27, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match.
ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 28, // For internal use by InputScalar() and TempInputScalar()
};
@@ -1033,12 +1033,11 @@ enum ImGuiButtonFlagsPrivate_
ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event)
ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using
ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item
ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release)
ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release). Prior to 2026/03/20 this implied ImGuiButtonFlags_NoHoldingActiveId but they are separate now.
ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release)
ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
//ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat -> use ImGuiItemFlags_ButtonRepeat instead.
ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping
ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable.
//ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press
//ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled
ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine
@@ -1246,7 +1245,8 @@ struct IMGUI_API ImGuiInputTextState
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool CursorCenterY; // set when we want scrolling to be centered over the cursor position (while resizing a word-wrapping field)
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool Edited; // edited this frame
bool EditedBefore; // edited since activated
bool EditedThisFrame; // edited this frame
bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version.
ImS8 LastMoveDirectionLR; // ImGuiDir_Left or ImGuiDir_Right. track last movement direction so when cursor cross over a word-wrapping boundaries we can display it on either line depending on last move.s
int ReloadSelectionStart;
@@ -1259,6 +1259,7 @@ struct IMGUI_API ImGuiInputTextState
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
void OnCharPressed(unsigned int c);
float GetPreferredOffsetX() const;
const char* GetText() { return TextA.Data ? TextA.Data : ""; }
// Cursor & Selection
void CursorAnimReset();
@@ -1508,8 +1509,8 @@ typedef ImBitArray<ImGuiKey_NamedKey_COUNT, -ImGuiKey_NamedKey_BEGIN> ImBitAr
#define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1
#define ImGuiKey_NavGamepadActivate (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceRight : ImGuiKey_GamepadFaceDown)
#define ImGuiKey_NavGamepadCancel (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceDown : ImGuiKey_GamepadFaceRight)
#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft
#define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp
#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft // Toggle menu layer. Hold to enable Windowing.
#define ImGuiKey_NavGamepadContextMenu ImGuiKey_GamepadFaceUp // Open context menu (same as Shift+F10)
enum ImGuiInputEventType
{
@@ -1958,7 +1959,7 @@ struct IMGUI_API ImGuiMultiSelectState
// Every instance of ImGuiViewport is in fact a ImGuiViewportP.
struct ImGuiViewportP : public ImGuiViewport
{
int BgFgDrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used
float BgFgDrawListsLastTimeActive[2]; // Last frame number the background (0) and foreground (1) draw lists were used
ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.
ImDrawData DrawDataP;
ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData
@@ -1972,7 +1973,7 @@ struct ImGuiViewportP : public ImGuiViewport
ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset
ImVec2 BuildWorkInsetMax; // "
ImGuiViewportP() { BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; }
ImGuiViewportP() { BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0f; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; }
~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }
// Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
@@ -2182,6 +2183,8 @@ struct ImGuiContextHook
ImGuiContextHook() { memset((void*)this, 0, sizeof(*this)); }
};
typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section);
//-----------------------------------------------------------------------------
// [SECTION] ImGuiContext (main Dear ImGui context)
//-----------------------------------------------------------------------------
@@ -2323,6 +2326,7 @@ struct ImGuiContext
ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow'
ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope)
ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer)
ImGuiItemFlags NavIdItemFlags;
ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItemByID()
ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0
ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat)
@@ -2330,6 +2334,8 @@ struct ImGuiContext
ImVector<ImGuiFocusScopeData> NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain.
ImGuiID NavHighlightActivatedId;
float NavHighlightActivatedTimer;
ImGuiID NavOpenContextMenuItemId;
ImGuiID NavOpenContextMenuWindowId;
ImGuiID NavNextActivateId; // Set by ActivateItemByID(), queued until next frame.
ImGuiActivateFlags NavNextActivateFlags;
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Gamepad
@@ -2459,6 +2465,7 @@ struct ImGuiContext
ImGuiInputTextDeactivatedState InputTextDeactivatedState;
ImFontBaked InputTextPasswordFontBackupBaked;
ImFontFlags InputTextPasswordFontBackupFlags;
ImGuiID InputTextReactivateId; // ID of InputText to reactivate on next frame (for io.ConfigInputTextEnterKeepActive behavior)
ImGuiID TempInputId; // Temporary text input when using Ctrl+Click on a slider, etc.
ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types
int BeginMenuDepth;
@@ -2504,8 +2511,11 @@ struct ImGuiContext
ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers
ImChunkStream<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries
ImChunkStream<ImGuiTableSettings> SettingsTables; // ImGuiTable .ini settings entries
// Hooks
ImVector<ImGuiContextHook> Hooks; // Hooks for extensions (e.g. test engine)
ImGuiID HookIdNext; // Next available HookId
ImGuiDemoMarkerCallback DemoMarkerCallback;
// Localization
const char* LocalizationTable[ImGuiLocKey_COUNT];
@@ -3035,8 +3045,9 @@ struct IMGUI_API ImGuiTable
ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0.
ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame.
ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held.
ImGuiTableColumnIdx LastHeldHeaderColumn; // Index of column header being held from previous frame.
ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared)
ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1
ImGuiTableColumnIdx ReorderColumnDstOrder; // Requested display order of column being reordered.
ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column.
ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column.
ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column.
@@ -3325,6 +3336,8 @@ namespace ImGui
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window);
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
IMGUI_API ImGuiMouseButton GetMouseButtonFromPopupFlags(ImGuiPopupFlags flags);
IMGUI_API bool IsPopupOpenRequestForItem(ImGuiPopupFlags flags, ImGuiID id);
IMGUI_API bool IsPopupOpenRequestForWindow(ImGuiPopupFlags flags);
// Tooltips
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags);
@@ -3549,6 +3562,7 @@ namespace ImGui
IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
IMGUI_API void TableRemove(ImGuiTable* table);
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table);
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table);
@@ -3638,6 +3652,7 @@ namespace ImGui
IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners
IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir);
IMGUI_API void ExtendHitBoxWhenNearViewportEdge(ImGuiWindow* window, ImRect* bb, float threshold, ImGuiAxis axis);
// Widgets low-level behaviors
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
@@ -3650,15 +3665,14 @@ namespace ImGui
IMGUI_API void TreeNodeDrawLineToChildNode(const ImVec2& target_pos);
IMGUI_API void TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data);
IMGUI_API void TreePushOverrideID(ImGuiID id);
IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id);
IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open);
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
// 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<float, float>(const char* format, ImGuiDataType data_type, float v); "
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float logarithmic_zero_epsilon, float zero_deadzone_size);
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, float logarithmic_zero_epsilon, float zero_deadzone_size);
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags);
template<typename T, typename SIGNED_T, typename FLOAT_T> IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);
template<typename T> IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v);
@@ -3676,7 +3690,7 @@ namespace ImGui
// InputText
IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API void InputTextDeactivateHook(ImGuiID id);
IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags);
IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return g.ActiveId == id && g.TempInputId == id; }
inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active
@@ -3712,6 +3726,9 @@ namespace ImGui
IMGUI_API bool BeginErrorTooltip();
IMGUI_API void EndErrorTooltip();
// Demo Doc Marker for e.g. imgui_explorer
IMGUI_API void DemoMarker(const char* file, int line, const char* section);
// Debug Tools
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free
IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255));
@@ -3731,7 +3748,7 @@ namespace ImGui
IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label);
IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb);
IMGUI_API void DebugNodeFont(ImFont* font);
IMGUI_API void DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask);
IMGUI_API void DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask);
IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph);
IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect = NULL); // ID used to facilitate persisting the "current" texture.
IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label);
+166 -53
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.6
// dear imgui, v1.92.7
// (main code and documentation)
// Help:
@@ -20,7 +20,7 @@
// - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui
// - Issues & support ........... https://github.com/ocornut/imgui/issues
// - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps)
// - Web version of the Demo .... https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html (w/ source code browser)
// - Web version of the Demo .... https://pthom.github.io/imgui_explorer (w/ source code browser)
// For FIRST-TIME users having issues compiling/linking/running:
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
@@ -167,6 +167,7 @@ CODE
- Home, End Scroll to top, scroll to bottom.
- Alt Toggle between scrolling layer and menu layer.
- Ctrl+Tab then Ctrl+Arrows Move window. Hold Shift to resize instead of moving.
- Menu or Shift+F10 Open context menu.
- Output when ImGuiConfigFlags_NavEnableKeyboard set,
- io.WantCaptureKeyboard flag is set when keyboard is claimed.
- io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
@@ -207,7 +208,7 @@ CODE
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, fewer bugs.
- Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version.
Or browse pthom's online imgui_explorer: https://pthom.github.io/imgui_explorer for a web version w/ source code browser.
- 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 in Wiki.
@@ -394,6 +395,19 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2026/03/19 (1.92.7) - MultiSelect: renamed ImGuiMultiSelectFlags_SelectOnClick to ImGuiMultiSelectFlags_SelectOnAuto.
- 2026/02/26 (1.92.7) - Separator: fixed a legacy quirk where Separator() was submitting a zero-height item for layout purpose, even though it draws a 1-pixel separator.
The fix could affect code e.g. computing height from multiple widgets in order to allocate vertical space for a footer or multi-line status bar. (#2657, #9263)
The "Console" example had such a bug:
float footer_height = style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
BeginChild("ScrollingRegion", { 0, -footer_height });
Should be:
float footer_height = style.ItemSpacing.y + style.SeparatorSize + ImGui::GetFrameHeightWithSpacing();
BeginChild("ScrollingRegion", { 0, -footer_height });
When such idiom was used and assuming zero-height Separator, it is likely that in 1.92.7 the resulting window will have unexpected 1 pixel scrolling range.
- 2026/02/23 (1.92.7) - Commented out legacy signature for Combo(), ListBox(), signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed.
- Old getter type: bool (*getter)(void* user_data, int idx, const char** out_text) // Set label + return bool. False replaced label with placeholder.
- New getter type: const char* (*getter)(void* user_data, int idx) // Return label or NULL/empty label if missing
- 2026/01/08 (1.92.6) - Commented out legacy names obsoleted in 1.90 (Sept 2023): 'BeginChildFrame()' --> 'BeginChild()' with 'ImGuiChildFlags_FrameStyle'. 'EndChildFrame()' --> 'EndChild()'. 'ShowStackToolWindow()' --> 'ShowIDStackToolWindow()'. 'IM_OFFSETOF()' --> 'offsetof()'.
- 2026/01/07 (1.92.6) - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). Default value has same meaning before and after.
- Refer to GitHub topic #9157 if you have any question.
@@ -1098,6 +1112,8 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
- Run the examples/ applications and explore them.
- Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide.
- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- See pthom's online imgui_explorer (https://pthom.github.io/imgui_explorer) which is a web
version of the demo with a source code browser.
- The demo covers most features of Dear ImGui, so you can read the code and see its output.
- See documentation and comments at the top of imgui.cpp + effectively imgui.h.
- 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the
@@ -1134,10 +1150,10 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
----------
Q: About the ID Stack system..
- Why is my widget not reacting when I click on it?
- How can I have widgets with an empty label?
- How can I have multiple widgets with the same label?
- How can I have multiple windows with the same label?
- How can I have multiple widgets with the same label? (using ## or PushID)
- How can I have widgets with an empty label? (using ##)
- How can I make a label dynamic? (using ###)
- General description of the label and ID Stack system.
Q: How can I display an image? What is ImTextureID, how does it work?
Q: How can I use my own math types instead of ImVec2?
Q: How can I interact with standard C++ types (such as std::string and std::vector)?
@@ -1294,6 +1310,7 @@ static const float FONT_DEFAULT_SIZE_BASE = 20.0f;
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
static const float NAV_ACTIVATE_HIGHLIGHT_TIMER = 0.10f; // Time to highlight an item activated by a shortcut.
static const float NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY = 0.60f; // Time to hold activation button (e.g. FaceDown) to turn the activation into a text input.
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
@@ -1340,6 +1357,7 @@ static void NavUpdateWindowing();
static void NavUpdateWindowingApplyFocus(ImGuiWindow* window);
static void NavUpdateWindowingOverlay();
static void NavUpdateCancelRequest();
static void NavUpdateContextMenuRequest();
static void NavUpdateCreateMoveRequest();
static void NavUpdateCreateTabbingRequest();
static float NavUpdatePageUpPageDown();
@@ -1494,7 +1512,8 @@ ImGuiStyle::ImGuiStyle()
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText()
SeparatorSize = 1.0f; // Thickness of border in Separator().
SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText().
SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
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.
@@ -1529,11 +1548,15 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
_MainScale *= scale_factor;
WindowPadding = ImTrunc(WindowPadding * scale_factor);
WindowRounding = ImTrunc(WindowRounding * scale_factor);
WindowBorderSize = ImTrunc(WindowBorderSize * scale_factor);
WindowMinSize = ImTrunc(WindowMinSize * scale_factor);
WindowBorderHoverPadding = ImTrunc(WindowBorderHoverPadding * scale_factor);
ChildRounding = ImTrunc(ChildRounding * scale_factor);
ChildBorderSize = ImTrunc(ChildBorderSize * scale_factor);
PopupRounding = ImTrunc(PopupRounding * scale_factor);
PopupBorderSize = ImTrunc(PopupBorderSize * scale_factor);
FramePadding = ImTrunc(FramePadding * scale_factor);
FrameBorderSize = ImTrunc(FrameBorderSize * scale_factor);
FrameRounding = ImTrunc(FrameRounding * scale_factor);
ItemSpacing = ImTrunc(ItemSpacing * scale_factor);
ItemInnerSpacing = ImTrunc(ItemInnerSpacing * scale_factor);
@@ -1550,16 +1573,21 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
ImageRounding = ImTrunc(ImageRounding * scale_factor);
ImageBorderSize = ImTrunc(ImageBorderSize * scale_factor);
TabRounding = ImTrunc(TabRounding * scale_factor);
TabBorderSize = ImTrunc(TabBorderSize * scale_factor);
TabMinWidthBase = ImTrunc(TabMinWidthBase * scale_factor);
TabMinWidthShrink = ImTrunc(TabMinWidthShrink * scale_factor);
TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : TabCloseButtonMinWidthSelected;
TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : TabCloseButtonMinWidthUnselected;
TabBarBorderSize = ImTrunc(TabBarBorderSize * scale_factor);
TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor);
TreeLinesSize = ImTrunc(TreeLinesSize * scale_factor);
TreeLinesRounding = ImTrunc(TreeLinesRounding * scale_factor);
DragDropTargetRounding = ImTrunc(DragDropTargetRounding * scale_factor);
DragDropTargetBorderSize = ImTrunc(DragDropTargetBorderSize * scale_factor);
DragDropTargetPadding = ImTrunc(DragDropTargetPadding * scale_factor);
ColorMarkerSize = ImTrunc(ColorMarkerSize * scale_factor);
SeparatorSize = ImTrunc(SeparatorSize * scale_factor);
SeparatorTextBorderSize = ImTrunc(SeparatorTextBorderSize * scale_factor);
SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor);
DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor);
DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor);
@@ -3242,8 +3270,7 @@ ImGuiListClipper::~ImGuiListClipper()
void ImGuiListClipper::Begin(int items_count, float items_height)
{
if (Ctx == NULL)
Ctx = ImGui::GetCurrentContext();
Ctx = ImGui::GetCurrentContext();
ImGuiContext& g = *Ctx;
ImGuiWindow* window = g.CurrentWindow;
@@ -3289,6 +3316,7 @@ void ImGuiListClipper::End()
}
TempData = NULL;
}
DisplayStart = DisplayEnd = ItemsCount; // Clear this so code which may be reused past last Step() won't trip on a non-empty range.
ItemsCount = -1;
}
@@ -3493,7 +3521,7 @@ bool ImGuiListClipper::Step()
return ret;
}
// Generic helper, equivalent to old ImGui::CalcListClipping() but statelesss
// Generic helper, equivalent to old ImGui::CalcListClipping() but stateless
void ImGui::CalcClipRectVisibleItemsY(const ImRect& clip_rect, const ImVec2& pos, float items_height, int* out_visible_start, int* out_visible_end)
{
*out_visible_start = ImMax((int)((clip_rect.Min.y - pos.y) / items_height), 0);
@@ -3622,6 +3650,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorSize)}, // ImGuiStyleVar_SeparatorSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
@@ -4185,6 +4214,8 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
NavWindow = NULL;
NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0;
NavLayer = ImGuiNavLayer_Main;
NavIdItemFlags = ImGuiItemFlags_None;
NavOpenContextMenuItemId = NavOpenContextMenuWindowId = 0;
NavNextActivateId = 0;
NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;
NavHighlightActivatedId = 0;
@@ -4254,6 +4285,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
MouseStationaryTimer = 0.0f;
InputTextPasswordFontBackupFlags = ImFontFlags_None;
InputTextReactivateId = 0;
TempInputId = 0;
memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue));
BeginMenuDepth = BeginComboDepth = 0;
@@ -4281,6 +4313,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
SettingsLoaded = false;
SettingsDirtyTimer = 0.0f;
HookIdNext = 0;
DemoMarkerCallback = NULL;
memset(LocalizationTable, 0, sizeof(LocalizationTable));
@@ -4596,11 +4629,12 @@ void ImGui::GcCompactTransientMiscBuffers()
// Not freed:
// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data)
// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
// FIXME: Consider exposing of elaborating GC policy, e.g. being able to trim excessive ImDrawList gaps. (#9303)
void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
{
window->MemoryCompacted = true;
window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
window->MemoryDrawListIdxCapacity = ImMin((int)(window->DrawList->IdxBuffer.Size * 1.05f), window->DrawList->IdxBuffer.Capacity);
window->MemoryDrawListVtxCapacity = ImMin((int)(window->DrawList->VtxBuffer.Size * 1.05f), window->DrawList->VtxBuffer.Capacity);
window->IDStack.clear();
window->DrawList->_ClearFreeMemory();
window->DC.ChildWindows.clear();
@@ -5050,6 +5084,13 @@ void ImGui::MemFree(void* ptr)
return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);
}
void ImGui::DemoMarker(const char* file, int line, const char* section)
{
ImGuiContext& g = *GImGui;
if (g.DemoMarkerCallback != NULL)
g.DemoMarkerCallback(file, line, section);
}
// We record the number of allocation in recent frames, as a way to audit/sanitize our guiding principles of "no allocations on idle/repeating frames"
void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size)
{
@@ -5153,12 +5194,12 @@ static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t draw
}
// Our ImDrawList system requires that there is always a command
if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount)
if (viewport->BgFgDrawListsLastTimeActive[drawlist_no] != (float)g.Time)
{
draw_list->_ResetForNewFrame();
draw_list->PushTexture(g.IO.Fonts->TexRef);
draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount;
viewport->BgFgDrawListsLastTimeActive[drawlist_no] = (float)g.Time;
}
return draw_list;
}
@@ -5523,7 +5564,7 @@ void ImGui::NewFrame()
// As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves.
if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId)
{
IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n");
IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() 0x%08X because it isn't marked alive anymore!\n", g.ActiveId);
ClearActiveID();
}
@@ -5537,6 +5578,8 @@ void ImGui::NewFrame()
g.ActiveIdIsJustActivated = false;
if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
g.TempInputId = 0;
if (g.InputTextReactivateId != 0 && g.InputTextReactivateId != g.DeactivatedItemData.ID)
g.InputTextReactivateId = 0;
if (g.ActiveId == 0)
{
g.ActiveIdUsingNavDirMask = 0x00;
@@ -5619,7 +5662,8 @@ void ImGui::NewFrame()
// Mark all windows as not visible and compact unused memory.
IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
const bool gc_all = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f);
const float memory_compact_start_time = gc_all ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
for (ImGuiWindow* window : g.Windows)
{
window->WasActive = window->Active;
@@ -5629,7 +5673,7 @@ void ImGui::NewFrame()
window->BeginCount = 0;
// Garbage collect transient buffers of recently unused windows
if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
if ((!window->WasActive || gc_all) && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
GcCompactTransientWindowBuffers(window);
}
@@ -5851,7 +5895,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
ImDrawList* draw_list = window->RootWindow->DrawList;
if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to strictly ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
ImDrawCmd cmd = draw_list->CmdBuffer.back();
IM_ASSERT(cmd.ElemCount == 6);
@@ -5947,10 +5991,14 @@ void ImGui::EndFrame()
}
g.WantTextInputNextFrame = ime_data->WantTextInput ? 1 : 0;
// Hide implicit/fallback "Debug" window if it hasn't been used
// Hide and unfocus implicit/fallback "Debug" window if it hasn't been used
g.WithinFrameScopeWithImplicitWindow = false;
if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
if (g.CurrentWindow && g.CurrentWindow->IsFallbackWindow && g.CurrentWindow->WriteAccessed == false)
{
g.CurrentWindow->Active = false;
if (g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow)
FocusWindow(NULL);
}
End();
// Update navigation: Ctrl+Tab, wrap-around requests
@@ -6037,7 +6085,7 @@ void ImGui::Render()
for (ImGuiViewportP* viewport : g.Viewports)
{
InitViewportDrawData(viewport);
if (viewport->BgFgDrawLists[0] != NULL)
if (viewport->BgFgDrawLists[0] != NULL && viewport->BgFgDrawListsLastTimeActive[0] == (float)g.Time)
AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
}
@@ -6069,7 +6117,7 @@ void ImGui::Render()
FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder);
// Add foreground ImDrawList (for each active viewport)
if (viewport->BgFgDrawLists[1] != NULL)
if (viewport->BgFgDrawLists[1] != NULL && viewport->BgFgDrawListsLastTimeActive[1] == (float)g.Time)
AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));
// We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch).
@@ -10029,11 +10077,12 @@ static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value)
// [Internal] Do not use directly
static ImGuiKeyChord GetMergedModsFromKeys()
{
// Bypass IsKeyDown() for the unlikely case where user used a ImGuiInputFlags_LockXXXX on those.
ImGuiKeyChord mods = 0;
if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; }
if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; }
if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; }
if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; }
if (ImGui::GetKeyData(ImGuiMod_Ctrl)->Down) { mods |= ImGuiMod_Ctrl; }
if (ImGui::GetKeyData(ImGuiMod_Shift)->Down) { mods |= ImGuiMod_Shift; }
if (ImGui::GetKeyData(ImGuiMod_Alt)->Down) { mods |= ImGuiMod_Alt; }
if (ImGui::GetKeyData(ImGuiMod_Super)->Down) { mods |= ImGuiMod_Super; }
return mods;
}
@@ -11059,6 +11108,8 @@ bool ImGui::ErrorLog(const char* msg)
return g.IO.ConfigErrorRecoveryEnableAssert;
}
// Display an error tooltip when same ID as HoveredId was submitted multiple times.
// See code in ItemHoverable() for an explanation of why we associate this error to HoveredId + code drawing of rectangles over individual items instances.
void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip()
{
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
@@ -12242,15 +12293,15 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to
// - Each popups may contain child windows, which is why we compare ->RootWindow!
// Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
// We step through every popup from bottom to top to validate their position relative to reference window.
bool ref_window_is_descendent_of_popup = false;
bool ref_window_is_descendant_of_popup = false;
for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
if (IsWindowWithinBeginStackOf(ref_window, popup_window))
{
ref_window_is_descendent_of_popup = true;
ref_window_is_descendant_of_popup = true;
break;
}
if (!ref_window_is_descendent_of_popup)
if (!ref_window_is_descendant_of_popup)
break;
}
}
@@ -12454,17 +12505,40 @@ ImGuiMouseButton ImGui::GetMouseButtonFromPopupFlags(ImGuiPopupFlags flags)
return ImGuiMouseButton_Right; // Default == 1
}
bool ImGui::IsPopupOpenRequestForItem(ImGuiPopupFlags popup_flags, ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
return true;
if (g.NavOpenContextMenuItemId == id && (IsItemFocused() || id == g.CurrentWindow->MoveId))
return true;
return false;
}
bool ImGui::IsPopupOpenRequestForWindow(ImGuiPopupFlags popup_flags)
{
ImGuiContext& g = *GImGui;
ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags);
if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
return true;
if (g.NavOpenContextMenuWindowId && g.CurrentWindow->ID)
if (IsWindowChildOf(g.NavWindow, g.CurrentWindow, false)) // This enable ordering to be used to disambiguate item vs window (#8803)
return true;
return false;
}
// Helper to open a popup if mouse button is released over the item
// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
if (IsPopupOpenRequestForItem(popup_flags, g.LastItemData.ID))
{
ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
OpenPopupEx(id, popup_flags);
}
}
@@ -12491,10 +12565,9 @@ bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag
ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
return false;
ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags);
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItem ID. Using LastItem ID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
if (IsPopupOpenRequestForItem(popup_flags, g.LastItemData.ID))
OpenPopupEx(id, popup_flags);
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
}
@@ -12506,10 +12579,8 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_fl
if (!str_id)
str_id = "window_context";
ImGuiID id = window->GetID(str_id);
ImGuiMouseButton mouse_button = GetMouseButtonFromPopupFlags(popup_flags);
if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
OpenPopupEx(id, popup_flags);
if (IsPopupOpenRequestForWindow(popup_flags))
OpenPopupEx(id, popup_flags);
return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
}
@@ -13033,6 +13104,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
window->NavLastIds[nav_layer] = id;
if (g.LastItemData.ID == id)
window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);
g.NavIdItemFlags = (g.LastItemData.ID == id) ? g.LastItemData.ItemFlags : ImGuiItemFlags_None;
if (id == g.ActiveIdIsAlive)
g.NavIdIsAlive = true;
@@ -13302,6 +13374,7 @@ static void ImGui::NavProcessItem()
SetNavFocusScope(g.CurrentFocusScopeId); // Will set g.NavFocusScopeId AND store g.NavFocusScopePath
g.NavFocusScopeId = g.CurrentFocusScopeId;
g.NavIdIsAlive = true;
g.NavIdItemFlags = item_flags;
if (g.LastItemData.ItemFlags & ImGuiItemFlags_HasSelectionUserData)
{
IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid);
@@ -13686,6 +13759,7 @@ static void ImGui::NavUpdate()
// Process NavCancel input (to close a popup, get back to parent, clear focus)
NavUpdateCancelRequest();
NavUpdateContextMenuRequest();
// Process manual activation request
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0;
@@ -13694,21 +13768,25 @@ static void ImGui::NavUpdate()
{
const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_NoOwner));
const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, 0, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, 0, ImGuiKeyOwner_NoOwner)));
const bool input_down = (nav_keyboard_active && (IsKeyDown(ImGuiKey_Enter, ImGuiKeyOwner_NoOwner) || IsKeyDown(ImGuiKey_KeypadEnter, ImGuiKeyOwner_NoOwner))) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput, ImGuiKeyOwner_NoOwner));
const bool input_pressed = input_down && ((nav_keyboard_active && (IsKeyPressed(ImGuiKey_Enter, 0, ImGuiKeyOwner_NoOwner) || IsKeyPressed(ImGuiKey_KeypadEnter, 0, ImGuiKeyOwner_NoOwner))) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, 0, ImGuiKeyOwner_NoOwner)));
const bool input_pressed_keyboard = nav_keyboard_active && (IsKeyPressed(ImGuiKey_Enter, 0, ImGuiKeyOwner_NoOwner) || IsKeyPressed(ImGuiKey_KeypadEnter, 0, ImGuiKeyOwner_NoOwner));
bool input_pressed_gamepad = false;
if (activate_down && nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_NoOwner) && (g.NavIdItemFlags & ImGuiItemFlags_Inputable)) // requires ImGuiItemFlags_Inputable to avoid retriggering regular buttons.
if (GetKeyData(ImGuiKey_NavGamepadActivate)->DownDurationPrev < NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY && GetKeyData(ImGuiKey_NavGamepadActivate)->DownDuration >= NAV_ACTIVATE_INPUT_WITH_GAMEPAD_DELAY)
input_pressed_gamepad = true;
if (g.ActiveId == 0 && activate_pressed)
{
g.NavActivateId = g.NavId;
g.NavActivateFlags = ImGuiActivateFlags_PreferTweak;
}
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed)
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (input_pressed_keyboard || input_pressed_gamepad))
{
g.NavActivateId = g.NavId;
g.NavActivateFlags = ImGuiActivateFlags_PreferInput;
}
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down))
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_pressed_keyboard || input_pressed_gamepad)) // FIXME-NAV: Unsure why input_pressed_xxx (migrated from input_down which was already dubious)
g.NavActivateDownId = g.NavId;
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed))
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed_keyboard || input_pressed_gamepad))
{
g.NavActivatePressedId = g.NavId;
NavHighlightActivated(g.NavId);
@@ -14170,6 +14248,31 @@ static void ImGui::NavUpdateCancelRequest()
}
}
static void ImGui::NavUpdateContextMenuRequest()
{
ImGuiContext& g = *GImGui;
g.NavOpenContextMenuItemId = g.NavOpenContextMenuWindowId = 0;
const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
const bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
if ((!nav_keyboard_active && !nav_gamepad_active) || g.NavWindow == NULL)
return;
bool request = false;
request |= nav_keyboard_active && (IsKeyReleased(ImGuiKey_Menu, ImGuiKeyOwner_NoOwner) || (IsKeyPressed(ImGuiKey_F10, ImGuiInputFlags_None, ImGuiKeyOwner_NoOwner) && g.IO.KeyMods == ImGuiMod_Shift));
request |= nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadContextMenu, ImGuiInputFlags_None, ImGuiKeyOwner_NoOwner);
if (!request)
return;
g.NavOpenContextMenuItemId = g.NavId;
g.NavOpenContextMenuWindowId = g.NavWindow->ID;
// Allow triggering for Begin()..BeginPopupContextItem(). A possible alternative would be to use g.NavLayer == ImGuiNavLayer_Menu.
if (g.NavId == g.NavWindow->GetID("#CLOSE") || g.NavId == g.NavWindow->GetID("#COLLAPSE"))
g.NavOpenContextMenuItemId = g.NavWindow->MoveId;
g.NavInputSource = ImGuiInputSource_Keyboard;
SetNavCursorVisibleAfterMove();
}
// Handle PageUp/PageDown/Home/End keys
// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request
// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference
@@ -14716,7 +14819,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
// Magic fallback to handle items with no assigned ID, e.g. Text(), Image()
// We build a throwaway ID based on current ID stack + relative AABB of items in window.
// THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
// THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
// We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
// Rely on keeping other window->LastItemXXX fields intact.
source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
@@ -14830,14 +14933,14 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s
// Store in heap
g.DragDropPayloadBufHeap.resize((int)data_size);
payload.Data = g.DragDropPayloadBufHeap.Data;
memcpy(payload.Data, data, data_size);
memcpy(payload.Data, data, (size_t)(int)data_size);
}
else if (data_size > 0)
{
// Store locally
memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
payload.Data = g.DragDropPayloadBufLocal;
memcpy(payload.Data, data, data_size);
memcpy(payload.Data, data, (size_t)(int)data_size);
}
else
{
@@ -15717,6 +15820,7 @@ static void ImGui::UpdateViewportsNewFrame()
main_viewport->FramebufferScale = g.IO.DisplayFramebufferScale;
IM_ASSERT(main_viewport->FramebufferScale.x > 0.0f && main_viewport->FramebufferScale.y > 0.0f);
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
for (ImGuiViewportP* viewport : g.Viewports)
{
// Lock down space taken by menu bars and status bars
@@ -15725,6 +15829,14 @@ static void ImGui::UpdateViewportsNewFrame()
viewport->WorkInsetMax = viewport->BuildWorkInsetMax;
viewport->BuildWorkInsetMin = viewport->BuildWorkInsetMax = ImVec2(0.0f, 0.0f);
viewport->UpdateWorkRect();
// Garbage collect transient buffers of recently BG/FG drawlists
for (int n = 0; n < IM_COUNTOF(viewport->BgFgDrawLists); n++)
if (viewport->BgFgDrawListsLastTimeActive[n] < memory_compact_start_time && viewport->BgFgDrawLists[n] != NULL)
{
IM_DELETE(viewport->BgFgDrawLists[n]);
viewport->BgFgDrawLists[n] = NULL;
}
}
}
@@ -16763,6 +16875,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
ImGuiDebugAllocInfo* info = &g.DebugAllocInfo;
Text("%d current allocations", info->TotalAllocCount - info->TotalFreeCount);
Text("Releasing selected unused buffers after: %.2f secs", g.IO.ConfigMemoryCompactTimer);
if (SmallButton("GC now")) { g.GcCompactAll = true; }
Text("Recent frames with allocations:");
int buf_size = IM_COUNTOF(info->LastEntriesBuf);
@@ -17332,7 +17445,7 @@ void ImGui::DebugNodeFont(ImFont* font)
src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y);
}
DebugNodeFontGlyphesForSrcMask(font, baked, ~0);
DebugNodeFontGlyphsForSrcMask(font, baked, ~0);
TreePop();
}
PopID();
@@ -17341,7 +17454,7 @@ void ImGui::DebugNodeFont(ImFont* font)
Unindent();
}
void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask)
void ImGui::DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask)
{
ImDrawList* draw_list = GetWindowDrawList();
const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
@@ -18112,7 +18225,7 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns*) {}
void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {}
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}
void ImGui::DebugNodeFont(ImFont*) {}
void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont*, ImFontBaked*, int) {}
void ImGui::DebugNodeFontGlyphsForSrcMask(ImFont*, ImFontBaked*, int) {}
void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}
+369 -228
View File
File diff suppressed because it is too large Load Diff
+7 -5
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.6
// dear imgui, v1.92.7
// (drawing and font code)
/*
@@ -1312,7 +1312,7 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
{
const float arc_length = ImAbs(a_max - a_min);
const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length));
const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), 1);
_PathArcToN(center, radius, a_min, a_max, arc_segment_count);
}
}
@@ -3205,7 +3205,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
if (font_cfg.Name[0] == '\0')
{
// Store a short copy of filename into into the font name for convenience
// Store a short copy of filename into the font name for convenience
const char* p;
for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "%s", p);
@@ -3213,7 +3213,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
}
// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
// NB: Transfer ownership of 'font_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
@@ -3260,7 +3260,9 @@ void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont*
shared_data->Font = new_font;
if (ImGuiContext* ctx = shared_data->Context)
{
if (ctx->FrameCount == 0 && old_font == NULL) // While this should work either way, we save ourselves the bother / debugging confusion of running ImGui code so early when it is not needed.
// While this should work either way, we save ourselves the bother / debugging confusion of running ImGui code so early when it is not needed.
// Also fixes erroneously rewriting style.FontSizeBase during init if adding default fonts.
if (old_font == NULL && ctx->Font == NULL && ctx->FontSizeBase == 0.0f)
continue;
if (ctx->IO.FontDefault == old_font)
+133 -64
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.6
// dear imgui, v1.92.7
// (tables and columns code)
/*
@@ -585,7 +585,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934)
table->InstanceInteracted = -1;
table->ContextPopupColumn = -1;
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
table->ReorderColumn = table->ReorderColumnDstOrder = table->ResizedColumn = table->LastResizedColumn = -1;
table->AutoFitSingleColumn = -1;
table->HoveredColumnBody = table->HoveredColumnBorder = -1;
for (int n = 0; n < columns_count; n++)
@@ -699,25 +699,23 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
}
// Handle reordering request
// Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test).
//// Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test).
if (table->InstanceCurrent == 0)
{
if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1)
table->ReorderColumn = -1;
table->LastHeldHeaderColumn = table->HeldHeaderColumn;
table->HeldHeaderColumn = -1;
if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0)
if (table->ReorderColumn != -1 && table->ReorderColumnDstOrder != -1)
{
// We need to handle reordering across hidden columns.
// In the configuration below, moving C to the right of E will lead to:
// ... C [D] E ---> ... [D] E C (Column name/index)
// ... 2 3 4 ... 2 3 4 (Display order)
IM_ASSERT(table->ReorderColumnDir == -1 || table->ReorderColumnDir == +1);
IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable);
ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn];
ImGuiTableColumn* dst_column = &table->Columns[(table->ReorderColumnDir < 0) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn];
TableSetColumnDisplayOrder(table, table->ReorderColumn, dst_column->DisplayOrder);
table->ReorderColumnDir = 0;
TableSetColumnDisplayOrder(table, table->ReorderColumn, table->ReorderColumnDstOrder);
table->ReorderColumnDstOrder = -1;
}
// Release
ImGuiContext& g = *GImGui;
if (g.ActiveId == 0) // FIXME: Need to revisit. See 38f5e5a.
table->ReorderColumn = -1;
//if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1)
// table->ReorderColumn = -1;
}
// Handle display order reset request
@@ -730,8 +728,7 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
}
}
// Note that TableSetupScrollFreeze() enforce a display order range for frozen columns.
// So reordering a column across the frozen column barrier is illegal and will be undone.
// Apply immediately. See TableQueueSetColumnDisplayOrder() for additional checks/constraints.
void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order)
{
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
@@ -755,6 +752,39 @@ void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_
table->IsSettingsDirty = true;
}
static int TableGetMaxDisplayOrderAllowed(ImGuiTable* table, int src_order, int dst_order)
{
dst_order = ImClamp(dst_order, 0, table->ColumnsCount - 1);
if (src_order == dst_order)
return dst_order;
// Cannot cross over the frozen column limit when interactively reordering.
// TableSetupScrollFreeze() enforce a display order range for frozen columns. Reordering across the frozen column barrier is illegal and will be undone.
if (table->FreezeColumnsRequest > 0)
dst_order = (src_order < table->FreezeColumnsRequest) ? ImMin(dst_order, (int)table->FreezeColumnsRequest - 1) : ImMax(dst_order, (int)table->FreezeColumnsRequest);
// Cannot cross over a column with the ImGuiTableColumnFlags_NoReorder flag.
int reorder_dir = (src_order < dst_order) ? +1 : -1;
for (int order_n = src_order; (src_order < dst_order && order_n <= dst_order) || (dst_order < src_order && order_n >= dst_order); order_n += reorder_dir)
if (table->Columns[table->DisplayOrderToIndex[order_n]].Flags & ImGuiTableColumnFlags_NoReorder)
{
dst_order = (order_n == src_order) ? src_order : order_n - reorder_dir;
break;
}
return dst_order;
}
// Reorder requested by user interaction.
void ImGui::TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order)
{
const int src_order = table->Columns[column_n].DisplayOrder;
table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)-1;
dst_order = TableGetMaxDisplayOrderAllowed(table, src_order, dst_order);
if (dst_order != src_order)
table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order;
}
// Adjust flags: default width mode + stretch columns are not allowed when auto extending
static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in)
{
@@ -1062,7 +1092,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
// Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping.
int visible_n = 0;
bool has_at_least_one_column_requesting_output = false;
bool offset_x_frozen = (table->FreezeColumnsCount > 0);
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
@@ -1077,7 +1106,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen
column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer);
if (offset_x_frozen && table->FreezeColumnsCount == visible_n)
if (offset_x_frozen && table->FreezeColumnsCount == order_n)
{
offset_x += work_rect.Min.x - table->OuterRect.Min.x;
offset_x_frozen = false;
@@ -1197,11 +1226,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->CannotSkipItemsQueue >>= 1;
}
if (visible_n < table->FreezeColumnsCount)
if (order_n < table->FreezeColumnsCount)
host_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x);
offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
visible_n++;
}
// In case the table is visible (e.g. decorations) but all columns clipped, we keep a column visible.
@@ -1282,7 +1310,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns)
if (table->FreezeColumnsRequest > 0)
table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x;
table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; // FIXME-FROZEN
if (table->FreezeRowsRequest > 0)
table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight;
table_instance->LastFrozenHeight = 0.0f;
@@ -1674,18 +1702,6 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0;
table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
// Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered.
// FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section)
for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++)
{
int order_n = table->DisplayOrderToIndex[column_n];
if (order_n != column_n && order_n >= table->FreezeColumnsRequest)
{
ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder);
ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]);
}
}
}
//-----------------------------------------------------------------------------
@@ -3121,7 +3137,7 @@ void ImGui::TableHeadersRow()
const int columns_count = TableGetColumnCount();
for (int column_n = 0; column_n < columns_count; column_n++)
{
if (!TableSetColumnIndex(column_n))
if (!TableSetColumnIndex(column_n) && table->LastHeldHeaderColumn != column_n)
continue;
// Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation)
@@ -3224,21 +3240,19 @@ void ImGui::TableHeader(const char* label)
// FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone.
if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive)
{
// While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x
table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
// - While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x
// - We need to handle reordering across hidden columns.
// In the configuration below, moving C to the right of E will lead to:
// ... C [D] E ---> ... [D] E C (Column name/index)
// ... 2 3 4 ... 2 3 4 (Display order)
// - The other constraints are enforced by TableQueueSetColumnDisplayOrder() which might early out.
table->InstanceInteracted = table->InstanceCurrent;
// We don't reorder: through the frozen<>unfrozen line, or through a column that is marked with ImGuiTableColumnFlags_NoReorder.
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x)
if (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL)
if (!((column->Flags | prev_column->Flags) & ImGuiTableColumnFlags_NoReorder))
if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (prev_column->IndexWithinEnabledSet < table->FreezeColumnsRequest))
table->ReorderColumnDir = -1;
TableQueueSetColumnDisplayOrder(table, column_n, prev_column->DisplayOrder);
if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x)
if (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL)
if (!((column->Flags | next_column->Flags) & ImGuiTableColumnFlags_NoReorder))
if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (next_column->IndexWithinEnabledSet < table->FreezeColumnsRequest))
table->ReorderColumnDir = +1;
TableQueueSetColumnDisplayOrder(table, column_n, next_column->DisplayOrder);
}
// Sort order arrow
@@ -3277,7 +3291,7 @@ void ImGui::TableHeader(const char* label)
SetItemTooltip("%.*s", (int)(label_end - label), label);
// We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden
if (IsMouseReleased(1) && IsItemHovered())
if (IsPopupOpenRequestForItem(ImGuiPopupFlags_None, id))
TableOpenContextMenu(column_n);
}
@@ -3294,7 +3308,7 @@ void ImGui::TableAngledHeadersRow()
// Which column needs highlight?
const ImGuiID row_id = GetID("##AngledHeaders");
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
int highlight_column_n = table->HighlightColumnHeader;
int highlight_column_n = (table->LastHeldHeaderColumn != -1) ? table->LastHeldHeaderColumn : table->HighlightColumnHeader;
if (highlight_column_n == -1 && table->HoveredColumnBody != -1)
if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive)))
highlight_column_n = table->HoveredColumnBody;
@@ -3348,13 +3362,14 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a); // vector from bottom-left to top-left, and from bottom-right to top-right
// Declare row, override and draw our own background
// FIXME-TABLE: Generally broken when overlapping frozen columns limit.
TableNextRow(ImGuiTableRowFlags_Headers, row_height);
TableNextColumn();
const ImRect row_r(table->WorkRect.Min.x, table->BgClipRect.Min.y, table->WorkRect.Max.x, table->RowPosY2);
table->DrawSplitter->SetCurrentChannel(draw_list, TABLE_DRAW_CHANNEL_BG0);
float clip_rect_min_x = table->BgClipRect.Min.x;
if (table->FreezeColumnsCount > 0)
clip_rect_min_x = ImMax(clip_rect_min_x, table->Columns[table->FreezeColumnsCount - 1].MaxX);
clip_rect_min_x = ImMax(clip_rect_min_x, table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsCount - 1]].MaxX);
TableSetBgColor(ImGuiTableBgTarget_RowBg0, 0); // Cancel
PushClipRect(table->BgClipRect.Min, table->BgClipRect.Max, false); // Span all columns
draw_list->AddRectFilled(ImVec2(table->BgClipRect.Min.x, row_r.Min.y), ImVec2(table->BgClipRect.Max.x, row_r.Max.y), GetColorU32(ImGuiCol_TableHeaderBg, 0.25f)); // FIXME-STYLE: Change row background with an arbitrary color.
@@ -3490,6 +3505,36 @@ bool ImGui::TableBeginContextMenuPopup(ImGuiTable* table)
return false;
}
// FIXME: Copied from MenuItem() for the purpose of being able to pass _SelectOnRelease (#9312)
static bool MenuItemForColumnReorder(const char* label, bool selected, bool enabled)
{
using namespace ImGui;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = offsets->DeclColumns(0.0f, label_size.x, 0.0f, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
ImGuiID id = GetID(label);
ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SpanAvailWidth;
if (g.ActiveId == id)
selectable_flags |= ImGuiSelectableFlags_Highlight; // Stays highlighted while dragging.
const bool has_been_moved = (g.ActiveId == id) && g.ActiveIdHasBeenEditedBefore; // But disable toggling once moved.
BeginDisabled(!enabled); // Don't use ImGuiSelectableFlags_Disabled so that Check mark is also affected.
bool ret = Selectable(label, false, selectable_flags, ImVec2(min_w, label_size.y)) && !has_been_moved; // Can't use IsMouseDragging(0) as button is released already.
if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && selected)
RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
EndDisabled();
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
return ret;
}
// Output context menu into current window (generally a popup)
// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data?
// Sections to display are pulled from 'flags_for_section_to_display', which is typically == table->Flags.
@@ -3506,17 +3551,17 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
return;
bool want_separator = false;
const int column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1;
ImGuiTableColumn* column = (column_n != -1) ? &table->Columns[column_n] : NULL;
const int context_column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1;
ImGuiTableColumn* context_column = (context_column_n != -1) ? &table->Columns[context_column_n] : NULL;
// Sizing
if (flags_for_section_to_display & ImGuiTableFlags_Resizable)
{
if (column != NULL)
if (context_column != NULL)
{
const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled;
const bool can_resize = !(context_column->Flags & ImGuiTableColumnFlags_NoResize) && context_column->IsEnabled;
if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableSizeOne), NULL, false, can_resize)) // "###SizeOne"
TableSetColumnWidthAutoSingle(table, column_n);
TableSetColumnWidthAutoSingle(table, context_column_n);
}
const char* size_all_desc;
@@ -3565,23 +3610,47 @@ void ImGui::TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags
Separator();
want_separator = true;
// While reordering: we calculate min/max allowed range once here so we can avoid a O(N log N) in the loop (because the query itself does a sweep scan).
// This assume that reordering constraints output a single range, otherwise would need to either call TableGetMaxDisplayOrderAllowed() for each item below, or cache this once per frame into columns.
const bool is_reordering = (g.ActiveId != 0 && g.ActiveIdWindow == g.CurrentWindow && table->ReorderColumn != -1 && g.ActiveIdHasBeenEditedBefore); // FIXME: This is a bit of a hack.
const int reorder_src_order = is_reordering ? table->Columns[table->ReorderColumn].DisplayOrder : -1;
const int reorder_min_order = is_reordering ? TableGetMaxDisplayOrderAllowed(table, reorder_src_order, 0) : 0;
const int reorder_max_order = is_reordering ? TableGetMaxDisplayOrderAllowed(table, reorder_src_order, table->ColumnsCount - 1) : table->ColumnsCount - 1;
PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
if (other_column->Flags & ImGuiTableColumnFlags_Disabled)
const int column_n = table->DisplayOrderToIndex[order_n];
ImGuiTableColumn* column = &table->Columns[column_n];
if (column->Flags & ImGuiTableColumnFlags_Disabled)
continue;
const char* name = TableGetColumnName(table, other_column_n);
const char* name = TableGetColumnName(table, column_n);
if (name == NULL || name[0] == 0)
name = "<Unknown>";
// Make sure we can't hide the last active column
bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;
if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1)
menu_item_active = false;
if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active))
other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled;
bool menu_item_enabled = (column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true;
if (column->IsUserEnabled && table->ColumnsEnabledCount <= 1)
menu_item_enabled = false;
if (is_reordering && (column->DisplayOrder < reorder_min_order || column->DisplayOrder > reorder_max_order))
menu_item_enabled = false;
if (MenuItemForColumnReorder(name, column->IsUserEnabled, menu_item_enabled))
column->IsUserEnabledNextFrame = !column->IsUserEnabled;
// Drag to reorder
// FIXME: It is currently not possible to reorder columns marked with ImGuiTableColumnFlags_NoHide.
if (IsItemActive() && IsMouseDragging(0) && g.ActiveIdSource == ImGuiInputSource_Mouse && (table->Flags & ImGuiTableFlags_Reorderable))
{
g.ActiveIdHasBeenEditedBefore = true; // Disable toggle in MenuItemForColumnReorder() + start dimming to display allowed reorder targets.
table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
if (!IsItemHovered())
{
int reorder_dir = (g.IO.MousePos.y < (g.LastItemData.Rect.Min.y + g.LastItemData.Rect.Max.y) * 0.5f) ? -1 : +1;
float reorder_amount = (reorder_dir < 0 ? g.LastItemData.Rect.Min.y - g.IO.MousePos.y : g.IO.MousePos.y - g.LastItemData.Rect.Max.y) / g.LastItemData.Rect.GetHeight();
int dst_order = column->DisplayOrder + (int)ImCeil(reorder_amount) * reorder_dir; // Estimated target order, will be validated and clamped.
TableQueueSetColumnDisplayOrder(table, column_n, dst_order);
}
}
}
PopItemFlag();
}
@@ -4051,7 +4120,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX);
BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder);
BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn);
BulletText("ResizedColumn: %d, HeldHeaderColumn: %d, ReorderColumn: %d", table->LastResizedColumn, table->LastHeldHeaderColumn, table->ReorderColumn);
for (int n = 0; n < table->InstanceCurrent + 1; n++)
{
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, n);
+268 -240
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.6
// dear imgui, v1.92.7
// (widgets code)
/*
@@ -653,6 +653,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child
}
}
if (flags & ImGuiButtonFlags_PressedOnRelease)
{
// FIXME: Traditionally ImGuiButtonFlags_PressedOnRelease never took ActiveId. Adding it in 2026-03-20 since ImGuiButtonFlags_NoHoldingActiveId can always be added.
// We don't yet perform an explicit ClearActiveID() to reduce scope of change, but this possibility could be investigated.
if (!(flags & ImGuiButtonFlags_NoHoldingActiveId))
SetActiveID(id, window); // Hold on ID
g.ActiveIdMouseButton = (ImS8)mouse_button_clicked;
}
}
if (flags & ImGuiButtonFlags_PressedOnRelease)
{
@@ -919,7 +927,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)
const ImU32 cross_col = GetColorU32(ImGuiCol_Text);
const ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f);
const float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;
const float cross_thickness = 1.0f; // FIXME-DPI
const float cross_thickness = 1.0f * (float)(int)g.Style._MainScale; // FIXME-DPI
window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness);
window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, cross_thickness);
@@ -974,6 +982,16 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size);
}
void ImGui::ExtendHitBoxWhenNearViewportEdge(ImGuiWindow* window, ImRect* bb, float threshold, ImGuiAxis axis)
{
ImRect window_rect = window->RootWindow->Rect();
ImRect viewport_rect = window->Viewport->GetMainRect();
if (window_rect.Min[axis] == viewport_rect.Min[axis] && bb->Min[axis] > window_rect.Min[axis] && bb->Min[axis] - threshold <= window_rect.Min[axis])
bb->Min[axis] = window_rect.Min[axis];
if (window_rect.Max[axis] == viewport_rect.Max[axis] && bb->Max[axis] < window_rect.Max[axis] && bb->Max[axis] + threshold >= window_rect.Max[axis])
bb->Max[axis] = window_rect.Max[axis];
}
void ImGui::Scrollbar(ImGuiAxis axis)
{
ImGuiContext& g = *GImGui;
@@ -1032,14 +1050,18 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_visible_v), (ImS64)1);
const float grab_h_minsize = ImMin(bb.GetSize()[axis], style.GrabMinSize);
const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v);
const float grab_h_pixels = (float)(int)ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v);
const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
// As a special thing, we allow scrollbar near the edge of a screen/viewport to be reachable with mouse at the extreme edge (#9276)
ImRect bb_hit = bb_frame;
ExtendHitBoxWhenNearViewportEdge(window, &bb_hit, g.Style.WindowBorderSize, (ImGuiAxis)(axis ^ 1));
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
bool held = false;
bool hovered = false;
ItemAdd(bb_frame, id, NULL, ImGuiItemFlags_NoNav);
ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
ButtonBehavior(bb_hit, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_visible_v);
float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max);
@@ -1529,7 +1551,7 @@ bool ImGui::TextLink(const char* label)
}
float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontBakedScale * 0.20f);
window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI
window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf), 1.0f * (float)(int)g.Style._MainScale); // FIXME-TEXT: Underline mode // FIXME-DPI
PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf));
RenderText(bb.Min, label, label_end);
@@ -1664,9 +1686,13 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness)
// We don't provide our width to the layout so that it doesn't get feed back into AutoFit
// FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell)
const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change.
// Between 1.71 and 1.92.7, we maintained a hack where a 1.0f thin Separator() would not impact layout.
// This was mostly chosen to allow backward compatibility with user's code assuming zero-height when calculating height for layout (e.g. bottom alignment of a status bar).
// In order to handle scaling we need to scale separator thickness and it would not makes sense to have a disparity depending on height.
////float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change.
const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness));
ItemSize(ImVec2(0.0f, thickness_for_layout));
ItemSize(ImVec2(0.0f, thickness));
if (ItemAdd(bb, 0))
{
@@ -1692,14 +1718,13 @@ void ImGui::Separator()
return;
// Those flags should eventually be configurable by the user
// FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f.
ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
// Only applies to legacy Columns() api as they relied on Separator() a lot.
if (window->DC.CurrentColumns)
flags |= ImGuiSeparatorFlags_SpanAllColumns;
SeparatorEx(flags, 1.0f);
SeparatorEx(flags, g.Style.SeparatorSize);
}
void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w)
@@ -2202,30 +2227,6 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa
return value_changed;
}
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
struct ImGuiGetNameFromIndexOldToNewCallbackData { void* UserData; bool (*OldCallback)(void*, int, const char**); };
static const char* ImGuiGetNameFromIndexOldToNewCallback(void* user_data, int idx)
{
ImGuiGetNameFromIndexOldToNewCallbackData* data = (ImGuiGetNameFromIndexOldToNewCallbackData*)user_data;
const char* s = NULL;
data->OldCallback(data->UserData, idx, &s);
return s;
}
bool ImGui::ListBox(const char* label, int* current_item, bool (*old_getter)(void*, int, const char**), void* user_data, int items_count, int height_in_items)
{
ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter };
return ListBox(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, height_in_items);
}
bool ImGui::Combo(const char* label, int* current_item, bool (*old_getter)(void*, int, const char**), void* user_data, int items_count, int popup_max_height_in_items)
{
ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter };
return Combo(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, popup_max_height_in_items);
}
#endif
//-------------------------------------------------------------------------
// [SECTION] Data Type and Data Formatting Helpers [Internal]
//-------------------------------------------------------------------------
@@ -2585,9 +2586,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision);
// Convert to parametric space, apply delta, convert back
float v_old_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
float v_old_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
float v_new_parametric = v_old_parametric + g.DragCurrentAccum;
v_cur = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
v_cur = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new_parametric, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
v_old_ref_for_accum_remainder = v_old_parametric;
}
else
@@ -2604,7 +2605,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
if (is_logarithmic)
{
// Convert to parametric space, apply delta, convert back
float v_new_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
float v_new_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder);
}
else
@@ -2680,6 +2681,20 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v
return false;
}
// Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp)
static bool TempInputIsClampEnabled(ImGuiSliderFlags flags, ImGuiDataType data_type, const void* p_min, const void* p_max)
{
if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL))
{
const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? ImGui::DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max
if (p_min == NULL || p_max == NULL || clamp_range_dir < 0)
return true;
if (clamp_range_dir == 0)
return ImGui::DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true;
}
return false;
}
// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional.
// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags)
@@ -2745,16 +2760,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
if (temp_input_is_active)
{
// Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp)
bool clamp_enabled = false;
if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL))
{
const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max
if (p_min == NULL || p_max == NULL || clamp_range_dir < 0)
clamp_enabled = true;
else if (clamp_range_dir == 0)
clamp_enabled = DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true;
}
const bool clamp_enabled = TempInputIsClampEnabled(flags, data_type, p_min, p_max);
return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL);
}
@@ -2954,14 +2960,14 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT)
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
{
if (v_min == v_max)
return 0.0f;
IM_UNUSED(data_type);
const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
if (is_logarithmic)
if (logarithmic_zero_epsilon > 0.0f) // == is_logarithmic from caller
{
bool flipped = v_max < v_min;
@@ -3011,7 +3017,7 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T
// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT)
template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, float zero_deadzone_halfsize)
{
// We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct"
// but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler.
@@ -3021,7 +3027,7 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T
return v_max;
TYPE result = (TYPE)0;
if (is_logarithmic)
if (logarithmic_zero_epsilon > 0.0f) // == is_logarithmic from caller
{
// Fudge min/max to avoid getting silly results close to zero
FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;
@@ -3126,7 +3132,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
const float mouse_abs_pos = g.IO.MousePos[axis];
if (g.ActiveIdIsJustActivated)
{
float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
if (axis == ImGuiAxis_Y)
grab_t = 1.0f - grab_t;
const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
@@ -3181,7 +3187,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
}
else if (g.SliderCurrentAccumDirty)
{
clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits
{
@@ -3195,10 +3201,10 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
clicked_t = ImSaturate(clicked_t + delta);
// Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator
TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))
v_new = RoundScalarWithFormatT<TYPE>(format, data_type, v_new);
float new_clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
float new_clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
if (delta > 0)
g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta);
@@ -3216,7 +3222,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
if (set_new_value)
{
TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
// Round to user desired precision based on format string
if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))
@@ -3238,7 +3244,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
else
{
// Output grab position so it can be displayed by the caller
float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
if (axis == ImGuiAxis_Y)
grab_t = 1.0f - grab_t;
const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
@@ -3346,7 +3352,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
if (temp_input_is_active)
{
// Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp)
const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0;
const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; // Don't use TempInputIsClampEnabled()
return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL);
}
@@ -3688,27 +3694,33 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
}
// Create text input in place of another active widget (e.g. used when doing a Ctrl+Click on drag/slider widgets)
// - This must be submitted right after the item it is overlaying.
// FIXME: Facilitate using this in variety of other situations.
// FIXME: Among other things, setting ImGuiItemFlags_AllowDuplicateId in LastItemData is currently correct but
// the expected relationship between TempInputXXX functions and LastItemData is a little fishy.
bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags)
bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
{
// On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id.
// We clear ActiveID on the first frame to allow the InputText() taking it back.
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const bool init = (g.TempInputId != id);
if (init)
ClearActiveID();
g.CurrentWindow->DC.CursorPos = bb.Min;
g.LastItemData.ItemFlags |= ImGuiItemFlags_AllowDuplicateId;
bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem);
ImVec2 backup_pos = window->DC.CursorPos;
window->DC.CursorPos = bb.Min;
g.LastItemData.ItemFlags |= ImGuiItemFlags_AllowDuplicateId; // Using ImGuiInputTextFlags_MergedItem above will skip ItemAdd() so we poke here.
bool value_changed = InputTextEx(label, NULL, buf, (int)buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_TempInput | ImGuiInputTextFlags_AutoSelectAll, callback, user_data);
KeepAliveID(id); // Not done because of ImGuiInputTextFlags_TempInput
if (init)
{
// First frame we started displaying the InputText widget, we expect it to take the active id.
IM_ASSERT(g.ActiveId == id);
g.TempInputId = g.ActiveId;
}
if (g.ActiveId != id)
g.TempInputId = 0;
window->DC.CursorPos = backup_pos;
return value_changed;
}
@@ -3731,29 +3743,28 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint;
g.LastItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; // Because TempInputText() uses ImGuiInputTextFlags_MergedItem it doesn't submit a new item, so we poke LastItemData.
bool value_changed = false;
if (TempInputText(bb, id, label, data_buf, IM_COUNTOF(data_buf), flags))
if (!TempInputText(bb, id, label, data_buf, IM_COUNTOF(data_buf), flags))
return false;
// Backup old value
size_t data_type_size = type_info->Size;
ImGuiDataTypeStorage data_backup;
memcpy(&data_backup, p_data, data_type_size);
// Apply new value (or operations) then clamp
DataTypeApplyFromText(data_buf, data_type, p_data, format, NULL);
if (p_clamp_min || p_clamp_max)
{
// Backup old value
size_t data_type_size = type_info->Size;
ImGuiDataTypeStorage data_backup;
memcpy(&data_backup, p_data, data_type_size);
// Apply new value (or operations) then clamp
DataTypeApplyFromText(data_buf, data_type, p_data, format, NULL);
if (p_clamp_min || p_clamp_max)
{
if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0)
ImSwap(p_clamp_min, p_clamp_max);
DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);
}
// Only mark as edited if new value is different
g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited;
value_changed = memcmp(&data_backup, p_data, data_type_size) != 0;
if (value_changed)
MarkItemEdited(id);
if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0)
ImSwap(p_clamp_min, p_clamp_max);
DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);
}
// Only mark as edited if new value is different
g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited;
bool value_changed = memcmp(&data_backup, p_data, data_type_size) != 0;
if (value_changed)
MarkItemEdited(id);
return value_changed;
}
@@ -3792,24 +3803,30 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
g.NextItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited;
flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint;
bool value_changed = false;
if (p_step == NULL)
const bool has_step_buttons = (p_step != NULL);
const float button_size = has_step_buttons ? GetFrameHeight() : 0.0f;
bool ret;
if (has_step_buttons)
{
if (InputText(label, buf, IM_COUNTOF(buf), flags))
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL);
}
else
{
const float button_size = GetFrameHeight();
// With Step Buttons
BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
PushID(label);
SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
if (InputText("", buf, IM_COUNTOF(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL);
ret = InputText("", buf, IM_COUNTOF(buf), flags); // PushID(label) + "" gives us the expected ID from outside point of view
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable);
}
else
{
// Without Step Buttons
ret = InputText(label, buf, IM_COUNTOF(buf), flags);
}
// Step buttons
// Apply
bool value_changed = ret ? DataTypeApplyFromText(buf, data_type, p_data, format, (flags & ImGuiInputTextFlags_ParseEmptyRefVal) ? p_data_default : NULL) : false;
// Step buttons
if (has_step_buttons)
{
const ImVec2 backup_frame_padding = style.FramePadding;
style.FramePadding.x = style.FramePadding.y;
if (flags & ImGuiInputTextFlags_ReadOnly)
@@ -4167,7 +4184,7 @@ static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)
char* dst = obj->TextA.Data + pos;
char* src = obj->TextA.Data + pos + n;
memmove(dst, src, obj->TextLen - n - pos + 1);
obj->Edited = true;
obj->EditedBefore = obj->EditedThisFrame = true;
obj->TextLen -= n;
}
@@ -4197,7 +4214,7 @@ static int STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const cha
memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos));
memcpy(text + pos, new_text, (size_t)new_text_len);
obj->Edited = true;
obj->EditedBefore = obj->EditedThisFrame = true;
obj->TextLen += new_text_len;
obj->TextA[obj->TextLen] = '\0';
@@ -4399,6 +4416,7 @@ void ImGui::PopPasswordFont()
// Return false to discard a character.
static bool InputTextFilterCharacter(ImGuiContext* ctx, ImGuiInputTextState* state, unsigned int* p_char, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard)
{
IM_ASSERT(state != NULL);
unsigned int c = *p_char;
ImGuiInputTextFlags flags = state->Flags;
@@ -4584,6 +4602,7 @@ static int InputTextLineIndexBuild(ImGuiInputTextFlags flags, ImGuiTextIndex* li
ImGuiContext& g = *GImGui;
int size = 0;
const char* s;
bool trailing_line_already_counted = false;
if (flags & ImGuiInputTextFlags_WordWrap)
{
for (s = buf; s < buf_end; s = (*s == '\n') ? s + 1 : s)
@@ -4604,6 +4623,7 @@ static int InputTextLineIndexBuild(ImGuiInputTextFlags flags, ImGuiTextIndex* li
}
else
{
// Inactive path: we don't know buf_end ahead of time.
const char* s_eol;
for (s = buf; ; s = s_eol + 1)
{
@@ -4612,6 +4632,7 @@ static int InputTextLineIndexBuild(ImGuiInputTextFlags flags, ImGuiTextIndex* li
if ((s_eol = strchr(s, '\n')) != NULL)
continue;
s += strlen(s);
trailing_line_already_counted = true;
break;
}
}
@@ -4622,11 +4643,8 @@ static int InputTextLineIndexBuild(ImGuiInputTextFlags flags, ImGuiTextIndex* li
line_index->Offsets.push_back(0);
size++;
}
if (buf_end > buf && buf_end[-1] == '\n' && size <= max_output_buffer_size)
{
if (buf_end > buf && buf_end[-1] == '\n' && !trailing_line_already_counted && size++ <= max_output_buffer_size)
line_index->Offsets.push_back((int)(buf_end - buf));
size++;
}
return size;
}
@@ -4727,12 +4745,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
draw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it.
draw_window->DC.CursorPos += style.FramePadding;
inner_size.x -= draw_window->ScrollbarSizes.x;
// FIXME: Could this be a ImGuiChildFlags to affect the SetLastItemDataForWindow() call?
g.LastItemData.ID = id;
g.LastItemData.ItemFlags = item_data_backup.ItemFlags;
g.LastItemData.StatusFlags = item_data_backup.StatusFlags;
}
else
{
// Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd)
ItemSize(total_bb, style.FramePadding.y);
if (!(flags & ImGuiInputTextFlags_MergedItem))
if (!(flags & ImGuiInputTextFlags_TempInput))
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))
return false;
}
@@ -4763,11 +4786,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_wordwrap)
wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize));
const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard)));
const bool user_clicked = hovered && io.MouseClicked[0];
const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
const bool input_requested_by_nav = (g.ActiveId != id) && (g.NavActivateId == id);
const bool input_requested_by_reactivate = (g.InputTextReactivateId == id); // for io.ConfigInputTextEnterKeepActive
const bool input_requested_by_user = (user_clicked) || (g.ActiveId == 0 && (flags & ImGuiInputTextFlags_TempInput));
const ImGuiID scrollbar_id = (is_multiline && state != NULL) ? GetWindowScrollbarID(draw_window, ImGuiAxis_Y) : 0;
const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == scrollbar_id;
const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == scrollbar_id;
bool clear_active_id = false;
bool select_all = false;
@@ -4775,8 +4800,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf);
const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state.
const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav);
const bool init_state = (init_make_active || user_scroll_active);
const bool init_make_active = (input_requested_by_user || input_requested_by_nav || input_requested_by_reactivate || user_scroll_finish);
if (init_reload_from_user_buf)
{
int new_len = (int)ImStrlen(buf);
@@ -4789,7 +4813,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb->select_start = state->ReloadSelectionStart;
state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; // will be clamped to bounds below
}
else if ((init_state && g.ActiveId != id) || init_changed_specs)
else if ((init_make_active && g.ActiveId != id) || init_changed_specs)
{
// Access state even if we don't own it yet.
state = &g.InputTextState;
@@ -4802,8 +4826,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode)
const int buf_len = (int)ImStrlen(buf);
IM_ASSERT(((buf_len + 1 <= buf_size) || (buf_len == 0 && buf_size == 0)) && "Is your input buffer properly zero-terminated?");
state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
memcpy(state->TextToRevertTo.Data, buf, buf_len + 1);
if (!user_scroll_finish)
{
state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
memcpy(state->TextToRevertTo.Data, buf, buf_len + 1);
}
// Preserve cursor position and undo/redo stack if we come back to same widget
// FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate?
@@ -4814,6 +4841,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Start edition
state->ID = id;
state->TextLen = buf_len;
state->EditedBefore = false;
if (!is_readonly)
{
state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string.
@@ -4899,7 +4927,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
ClearActiveID();
// Release focus when we click outside
if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560
if (g.ActiveId == id && io.MouseClicked[0] && !init_make_active) //-V560
clear_active_id = true;
// Lock the decision of whether we are going to take the path displaying the cursor or selection
@@ -4929,7 +4957,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (g.ActiveId == id)
{
IM_ASSERT(state != NULL);
state->Edited = false;
state->EditedThisFrame = false;
state->BufCapacity = buf_size;
state->Flags = flags;
state->WrapWidth = wrap_width;
@@ -5070,7 +5098,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
const bool is_enter = Shortcut(ImGuiKey_Enter, f_repeat, id) || Shortcut(ImGuiKey_KeypadEnter, f_repeat, id);
const bool is_ctrl_enter = Shortcut(ImGuiMod_Ctrl | ImGuiKey_Enter, f_repeat, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_KeypadEnter, f_repeat, id);
const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false));
const bool is_shift_enter = Shortcut(ImGuiMod_Shift | ImGuiKey_Enter, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_KeypadEnter, f_repeat, id);
const bool is_gamepad_validate = nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, false);
const bool is_cancel = Shortcut(ImGuiKey_Escape, f_repeat, id) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, f_repeat, id));
// FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of.
@@ -5104,17 +5133,20 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
}
else if (is_enter || is_ctrl_enter || is_gamepad_validate)
else if (is_enter || is_ctrl_enter || is_shift_enter || is_gamepad_validate)
{
// Determine if we turn Enter into a \n character
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line != is_ctrl_enter))
bool is_new_line = is_multiline && !is_gamepad_validate && (is_shift_enter || (is_enter && !ctrl_enter_for_new_line) || (is_ctrl_enter && ctrl_enter_for_new_line));
if (!is_new_line)
{
validated = true;
validated = clear_active_id = true;
if (io.ConfigInputTextEnterKeepActive && !is_multiline)
{
// Queue reactivation, so that e.g. IsItemDeactivatedAfterEdit() will work. (#9001)
state->SelectAll(); // No need to scroll
else
clear_active_id = true;
g.InputTextReactivateId = id; // Mark for reactivation on next frame
}
}
else if (!is_readonly)
{
@@ -5210,7 +5242,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
}
// Process callbacks and apply result back to user's buffer.
// Process revert and user callbacks
const char* apply_new_text = NULL;
int apply_new_text_length = 0;
if (g.ActiveId == id)
@@ -5240,110 +5272,99 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
}
// FIXME-OPT: We always reapply the live buffer back to the input buffer before clearing ActiveId,
// even though strictly speaking it wasn't modified on this frame. Should mark dirty state from the stb_textedit callbacks.
// If we do that, need to ensure that as special case, 'validated == true' also writes back.
// This also allows the user to use InputText() without maintaining any user-side storage.
// (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object
// unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize).
const bool apply_edit_back_to_user_buffer = true;// !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
if (apply_edit_back_to_user_buffer)
// User callback
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0)
{
// Apply current edited text immediately.
// Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
IM_ASSERT(callback != NULL);
// User callback
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0)
// The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
ImGuiInputTextFlags event_flag = 0;
ImGuiKey event_key = ImGuiKey_None;
if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, 0, id))
{
IM_ASSERT(callback != NULL);
// The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
ImGuiInputTextFlags event_flag = 0;
ImGuiKey event_key = ImGuiKey_None;
if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, 0, id))
{
event_flag = ImGuiInputTextFlags_CallbackCompletion;
event_key = ImGuiKey_Tab;
}
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow))
{
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_UpArrow;
}
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow))
{
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_DownArrow;
}
else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited)
{
event_flag = ImGuiInputTextFlags_CallbackEdit;
}
else if (flags & ImGuiInputTextFlags_CallbackAlways)
{
event_flag = ImGuiInputTextFlags_CallbackAlways;
}
if (event_flag)
{
ImGuiInputTextCallbackData callback_data;
callback_data.Ctx = &g;
callback_data.ID = id;
callback_data.Flags = flags;
callback_data.EventFlag = event_flag;
callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated);
callback_data.UserData = callback_user_data;
// FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925
char* callback_buf = is_readonly ? buf : state->TextA.Data;
IM_ASSERT(callback_buf == state->TextSrc);
state->CallbackTextBackup.resize(state->TextLen + 1);
memcpy(state->CallbackTextBackup.Data, callback_buf, state->TextLen + 1);
callback_data.EventKey = event_key;
callback_data.Buf = callback_buf;
callback_data.BufTextLen = state->TextLen;
callback_data.BufSize = state->BufCapacity;
callback_data.BufDirty = false;
callback_data.CursorPos = state->Stb->cursor;
callback_data.SelectionStart = state->Stb->select_start;
callback_data.SelectionEnd = state->Stb->select_end;
// Call user code
callback(&callback_data);
// Read back what user may have modified
callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback
IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields
IM_ASSERT(callback_data.BufSize == state->BufCapacity);
IM_ASSERT(callback_data.Flags == flags);
if (callback_data.BufDirty || callback_data.CursorPos != state->Stb->cursor)
state->CursorFollow = true;
state->Stb->cursor = ImClamp(callback_data.CursorPos, 0, callback_data.BufTextLen);
state->Stb->select_start = ImClamp(callback_data.SelectionStart, 0, callback_data.BufTextLen);
state->Stb->select_end = ImClamp(callback_data.SelectionEnd, 0, callback_data.BufTextLen);
if (callback_data.BufDirty)
{
// Callback may update buffer and thus set buf_dirty even in read-only mode.
IM_ASSERT(callback_data.BufTextLen == (int)ImStrlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen);
state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
state->CursorAnimReset();
}
}
event_flag = ImGuiInputTextFlags_CallbackCompletion;
event_key = ImGuiKey_Tab;
}
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow))
{
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_UpArrow;
}
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow))
{
event_flag = ImGuiInputTextFlags_CallbackHistory;
event_key = ImGuiKey_DownArrow;
}
else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->EditedThisFrame)
{
event_flag = ImGuiInputTextFlags_CallbackEdit;
}
else if (flags & ImGuiInputTextFlags_CallbackAlways)
{
event_flag = ImGuiInputTextFlags_CallbackAlways;
}
// Will copy result string if modified
if (!is_readonly && strcmp(state->TextSrc, buf) != 0)
if (event_flag)
{
apply_new_text = state->TextSrc;
apply_new_text_length = state->TextLen;
value_changed = true;
ImGuiInputTextCallbackData callback_data;
callback_data.Ctx = &g;
callback_data.ID = id;
callback_data.Flags = flags;
callback_data.EventFlag = event_flag;
callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated);
callback_data.UserData = callback_user_data;
// FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925
char* callback_buf = is_readonly ? buf : state->TextA.Data;
IM_ASSERT(callback_buf == state->TextSrc);
state->CallbackTextBackup.resize(state->TextLen + 1);
memcpy(state->CallbackTextBackup.Data, callback_buf, state->TextLen + 1);
callback_data.EventKey = event_key;
callback_data.Buf = callback_buf;
callback_data.BufTextLen = state->TextLen;
callback_data.BufSize = state->BufCapacity;
callback_data.BufDirty = false;
callback_data.CursorPos = state->Stb->cursor;
callback_data.SelectionStart = state->Stb->select_start;
callback_data.SelectionEnd = state->Stb->select_end;
// Call user code
callback(&callback_data);
// Read back what user may have modified
callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback
IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields
IM_ASSERT(callback_data.BufSize == state->BufCapacity);
IM_ASSERT(callback_data.Flags == flags);
if (callback_data.BufDirty || callback_data.CursorPos != state->Stb->cursor)
state->CursorFollow = true;
state->Stb->cursor = ImClamp(callback_data.CursorPos, 0, callback_data.BufTextLen);
state->Stb->select_start = ImClamp(callback_data.SelectionStart, 0, callback_data.BufTextLen);
state->Stb->select_end = ImClamp(callback_data.SelectionEnd, 0, callback_data.BufTextLen);
if (callback_data.BufDirty)
{
// Callback may update buffer and thus set buf_dirty even in read-only mode.
IM_ASSERT(callback_data.BufTextLen == (int)ImStrlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen);
state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
state->CursorAnimReset();
}
}
}
// Will copy result string if modified.
// FIXME-OPT: Could mark dirty state from the stb_textedit callbacks
if (!is_readonly && strcmp(state->TextSrc, buf) != 0)
{
apply_new_text = state->TextSrc;
apply_new_text_length = state->TextLen;
value_changed = true;
}
}
// Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details)
// This is used when e.g. losing focus or tabbing out into another InputText() which may already be using the temp buffer.
if (g.InputTextDeactivatedState.ID == id)
{
if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0)
@@ -5356,12 +5377,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
g.InputTextDeactivatedState.ID = 0;
}
// Copy result to user buffer. This can currently only happen when (g.ActiveId == id)
// Write back result to user buffer. This can currently only happen when (g.ActiveId == id) or when just deactivated.
// - As soon as the InputText() is active, our stored in-widget value gets priority over any underlying modification of the user buffer.
// - Make sure we always reapply the live buffer back to the input/user buffer before clearing ActiveId, even thought strictly speaking
// it was not modified on this frame. This allows the user to use InputText() without maintaining any user-side storage.
// (PS: if you use this property together with ImGuiInputTextFlags_CallbackResize, you are at the risk of recreating a temporary
// allocated/string object every frame. Which in the grand scheme of scheme is nothing, but isn't dear imgui vibe).
if (apply_new_text != NULL)
{
//// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size
//// of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used
//// without any storage on user's side.
IM_ASSERT(apply_new_text_length >= 0);
if (is_resizable)
{
@@ -5370,7 +5393,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
callback_data.ID = id;
callback_data.Flags = flags;
callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated);
callback_data.EventActivated = (state != NULL && g.ActiveId == state->ID && g.ActiveIdIsJustActivated);
callback_data.Buf = buf;
callback_data.BufTextLen = apply_new_text_length;
callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1);
@@ -5530,7 +5553,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (render_selection)
{
const ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
const float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
const float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME-DPI: those offsets should be part of the style? they don't play so well with multi-line selection.
const float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
const float bg_eol_width = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
@@ -5559,7 +5582,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
rect.Min.y = draw_pos.y - draw_scroll.y + line_n * g.FontSize;
rect.Max.x = rect.Min.x + rect_width;
rect.Max.y = rect.Min.y + bg_offy_dn + g.FontSize;
rect.Min.y -= bg_offy_up;
rect.Min.y += bg_offy_up;
rect.ClipWith(clip_rect);
draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
}
@@ -5567,7 +5590,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
// Find render position for right alignment (single-line only)
if (g.ActiveId != id && flags & ImGuiInputTextFlags_ElideLeft)
if (g.ActiveId != id && (flags & ImGuiInputTextFlags_ElideLeft) && !render_cursor && !render_selection)
draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x);
//draw_scroll.x = state->Scroll.x; // Preserve scroll when inactive?
@@ -5588,7 +5611,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll);
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031)
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031)
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
// This is required for some backends (SDL3) to start emitting character/text inputs.
@@ -6446,7 +6469,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
if (g.Style.FrameBorderSize > 0.0f)
RenderFrameBorder(bb.Min, bb.Max, rounding);
else
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border // FIXME-DPI
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding, 0, 1.0f * (float)(int)g.Style._MainScale); // Color buttons are often in need of some sort of border // FIXME-DPI
}
// Drag and Drop Source
@@ -6726,6 +6749,8 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char
return TreeNodeBehavior(id, flags, label, label_end);
}
// The reason those two functions are not yet in public API is because I would like to design a more feature-full and generic API for this.
// They are otherwise function (cc: #3823, #9251, #7553, #6754, #5423, #2958, #2079, #1947, #1131, #722)
bool ImGui::TreeNodeGetOpen(ImGuiID storage_id)
{
ImGuiContext& g = *GImGui;
@@ -6733,15 +6758,16 @@ bool ImGui::TreeNodeGetOpen(ImGuiID storage_id)
return storage->GetInt(storage_id, 0) != 0;
}
void ImGui::TreeNodeSetOpen(ImGuiID storage_id, bool open)
void ImGui::TreeNodeSetOpen(ImGuiID storage_id, bool is_open)
{
ImGuiContext& g = *GImGui;
ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage;
storage->SetInt(storage_id, open ? 1 : 0);
storage->SetInt(storage_id, is_open ? 1 : 0);
}
bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags)
{
// Leaf node always open a new tree/id scope. If you never use it, add ImGuiTreeNodeFlags_NoTreePushOnOpen.
if (flags & ImGuiTreeNodeFlags_Leaf)
return true;
@@ -8165,10 +8191,13 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags
{
ImGuiButtonFlags button_flags = *p_button_flags;
button_flags |= ImGuiButtonFlags_NoHoveredOnFocus;
if ((!selected || (g.ActiveId == id && g.ActiveIdHasBeenPressedBefore)) && !(ms->Flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
button_flags = (button_flags | ImGuiButtonFlags_PressedOnClick) & ~ImGuiButtonFlags_PressedOnClickRelease;
else
button_flags &= ~(ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease);
if (ms->Flags & ImGuiMultiSelectFlags_SelectOnClickAlways)
button_flags |= ImGuiButtonFlags_PressedOnClick;
else if (ms->Flags & ImGuiMultiSelectFlags_SelectOnClickRelease)
button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
else // ImGuiMultiSelectFlags_SelectOnAuto
button_flags |= (!selected || (g.ActiveId == id && g.ActiveIdHasBeenPressedBefore)) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnClickRelease;
*p_button_flags = button_flags;
}
}
@@ -8288,7 +8317,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
// Box-select
ImGuiInputSource input_source = (g.NavJustMovedToId == id || g.NavActivateId == id) ? g.NavInputSource : ImGuiInputSource_Mouse;
if (flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d))
if (selected == false && !g.BoxSelectState.IsActive && !g.BoxSelectState.IsStarting && input_source == ImGuiInputSource_Mouse && g.IO.MouseClickedCount[0] == 1)
if (!g.BoxSelectState.IsActive && !g.BoxSelectState.IsStarting && input_source == ImGuiInputSource_Mouse && g.IO.MouseClickedCount[0] == 1)
BoxSelectPreStartDrag(ms->BoxSelectId, item_data);
//----------------------------------------------------------------------------------------
@@ -9232,11 +9261,12 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
PushID(label);
if (!enabled)
BeginDisabled();
const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
bool pressed;
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{
// Menu inside a horizontal menu bar
@@ -9244,9 +9274,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f);
float w = label_size.x;
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y));
pressed = Selectable("", menu_is_open, selectable_flags, label_size);
LogSetNextTextDecoration("[", "]");
RenderText(text_pos, label);
PopStyleVar();
@@ -9260,7 +9289,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.)
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float min_w = offsets->DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
@@ -9445,17 +9474,16 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
BeginDisabled();
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{
// Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
// Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark.
float w = label_size.x;
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f);
pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f));
pressed = Selectable("", selected, selectable_flags, ImVec2(label_size.x, 0.0f));
PopStyleVar();
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
RenderText(text_pos, label);
@@ -9469,7 +9497,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f;
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float min_w = offsets->DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(pos.x, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
@@ -10545,7 +10573,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Click to Select a tab
// Allow the close button to overlap
ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
ImGuiButtonFlags button_flags = ((ImGuiButtonFlags)(is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
if (g.DragDropActive)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
bool hovered, held, pressed;
+2 -2
View File
@@ -315,7 +315,7 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
// but we'll now add more waste for everything we've visited
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
@@ -470,7 +470,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
// stitched back in
cur = *res.prev_link;
if (cur->x < res.x) {
+1 -1
View File
@@ -886,7 +886,7 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, fl
// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
// the same as stbtt_GetCodepointBitmap, but you can specify a subpixel
// shift for the character
STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
+2 -2
View File
@@ -1347,7 +1347,7 @@ void FullscreenUI::DrawLandingWindow()
if (ImGui::Shortcut(ImGuiKey_GamepadBack) || ImGui::Shortcut(ImGuiKey_F1))
OpenAboutWindow();
if (ImGui::Shortcut(ImGuiKey_NavGamepadInput) || ImGui::Shortcut(ImGuiKey_Space))
if (ImGui::Shortcut(ImGuiKey_NavGamepadContextMenu) || ImGui::Shortcut(ImGuiKey_Space))
SwitchToGameList();
else if (ImGui::Shortcut(ImGuiKey_NavGamepadMenu) || ImGui::Shortcut(ImGuiKey_F11))
DoToggleFullscreen();
@@ -2564,7 +2564,7 @@ void FullscreenUI::DrawGameListWindow()
EndFullscreenWindow();
if (ImGui::IsKeyPressed(ImGuiKey_NavGamepadInput, false) || ImGui::IsKeyPressed(ImGuiKey_F1, false))
if (ImGui::IsKeyPressed(ImGuiKey_NavGamepadContextMenu, false) || ImGui::IsKeyPressed(ImGuiKey_F1, false))
{
s_game_list_view = (s_game_list_view == GameListView::Grid) ? GameListView::List : GameListView::Grid;
}
+1 -1
View File
@@ -2302,7 +2302,7 @@ void ImGuiFullscreen::DrawFileSelector()
ImGui::PopStyleColor(1);
if ((ImGui::Shortcut(ImGuiKey_Backspace, false) || ImGui::Shortcut(ImGuiKey_NavGamepadInput, false)) &&
if ((ImGui::Shortcut(ImGuiKey_Backspace, false) || ImGui::Shortcut(ImGuiKey_NavGamepadContextMenu, false)) &&
(!s_file_selector_items.empty() && s_file_selector_items.front().display_name == ICON_FA_FOLDER_OPEN " <Parent Directory>"))
{
parent_wanted = true;