mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-15 19:43:28 +01:00
Merge branch 'master' into docking
# Conflicts: # examples/imgui_examples.sln # examples/imgui_impl_dx12.cpp # examples/imgui_impl_dx12.h # examples/imgui_impl_opengl3.cpp # imgui.cpp # imgui_demo.cpp # imgui_internal.h # imgui_widgets.cpp
This commit is contained in:
commit
fa004ae79a
@ -104,6 +104,19 @@ Other changes:
|
||||
VERSION 1.79 WIP (In Progress)
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Breaking Changes:
|
||||
|
||||
- Fonts: Removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied
|
||||
after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font.
|
||||
It was also getting in the way of better font scaling, so let's get rid of it now!
|
||||
If you used DisplayOffset it was probably in association to rasterizing a font at a specific size,
|
||||
in which case the corresponding offset may be reported into GlyphOffset. (#1619)
|
||||
- Renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), REVERTED CHANGE FROM 1.77.
|
||||
For variety of reason this is more self-explanatory.
|
||||
- Removed return value from OpenPopupOnItemClick() - returned true on mouse release on item - because it
|
||||
is inconsistent with other popups API and makes others misleading. It's also and unnecessary: you can
|
||||
use IsWindowAppearing() after BeginPopup() for a similar result.
|
||||
|
||||
Other Changes:
|
||||
|
||||
- Window: Fixed using non-zero pivot in SetNextWindowPos() when the window is collapsed. (#3433)
|
||||
@ -111,6 +124,7 @@ Other Changes:
|
||||
- Nav: Fixed using Alt to toggle the Menu layer when inside a Modal window. (#787)
|
||||
- Scrolling: Fixed SetScrollHere functions edge snapping when called during a frame where ContentSize
|
||||
is changing (issue introduced in 1.78). (#3452).
|
||||
- InputText: Added support for Page Up/Down in InputTextMultiline(). (#3430) [@Xipiryon]
|
||||
- InputText: Added selection helpers in ImGuiInputTextCallbackData().
|
||||
- InputText: Added ImGuiInputTextFlags_CallbackEdit to modify internally owned buffer after an edit.
|
||||
(note that InputText() already returns true on edit, the callback is useful mainly to manipulate the
|
||||
@ -119,27 +133,53 @@ Other Changes:
|
||||
It is a rather unusual or useless combination of features but no reason it shouldn't work!
|
||||
- InputText: Fixed minor scrolling glitch when erasing trailing lines in InputTextMultiline().
|
||||
- InputText: Fixed cursor being partially covered after using Ctrl+End key.
|
||||
- InputText: Fixed callback's helper DeleteChars() function when cursor is inside the deleted block. (#3454).
|
||||
- InputText: Fixed callback's helper DeleteChars() function when cursor is inside the deleted block. (#3454)
|
||||
- InputText: Made pressing Down arrow on the last line when it doesn't have a carriage return not move to
|
||||
the end of the line (so it is consistent with Up arrow, and behave same as Notepad and Visual Studio.
|
||||
Note that some other text editors instead would move the crusor to the end of the line). [@Xipiryon]
|
||||
- DragFloat, DragScalar: Fixed ImGuiSliderFlags_ClampOnInput not being honored in the special case
|
||||
where v_min == v_max. (#3361)
|
||||
- SliderInt, SliderScalar: Fixed reaching of maximum value with inverted integer min/max ranges, both
|
||||
with signed and unsigned types. Added reverse Sliders to Demo. (#3432, #3449) [@rokups]
|
||||
- Text: Bypass unnecessary formatting when using the TextColored()/TextWrapped()/TextDisabled() helpers
|
||||
with a "%s" format string. (#3466)
|
||||
- BeginMenuBar: Fixed minor bug where CursorPosMax gets pushed to CursorPos prior to calling BeginMenuBar(),
|
||||
so e.g. calling the function at the end of a window would often add +ItemSpacing.y to scrolling range.
|
||||
- TreeNode, CollapsingHeader: Made clicking on arrow toggle toggle the open state on the Mouse Down event
|
||||
rather than the Mouse Down+Up sequence, even if the _OpenOnArrow flag isn't set. This is standard behavior
|
||||
and amends the change done in 1.76 which only affected cases were _OpenOnArrow flag was set.
|
||||
(This is also necessary to support full multi/range-select/drag and drop operations.)
|
||||
- Tab Bar: Added TabItemButton() to submit tab that behave like a button. (#3291) [@Xipiryon]
|
||||
- Tab Bar: Added ImGuiTabItemFlags_Leading and ImGuiTabItemFlags_Trailing flags to position tabs or button
|
||||
at either end of the tab bar. Those tabs won't be part of the scrolling region, and when reordering cannot
|
||||
be moving outside of their section. Most often used with TabItemButton(). (#3291) [@Xipiryon]
|
||||
- Tab Bar: Added ImGuiTabItemFlags_NoReorder flag to disable reordering a given tab.
|
||||
- Tab Bar: Keep tab item close button visible while dragging a tab (independent of hovering state).
|
||||
- Tab Bar: Fixed a small bug where closing a tab that is not selected would leave a tab hole for a frame.
|
||||
- Tab Bar: Fixed a small bug where scrolling buttons (with ImGuiTabBarFlags_FittingPolicyScroll) would
|
||||
generate an unnecessary extra draw call.
|
||||
- Tab Bar: Fixed a small bug where toggling a tab bar from Reorderable to not Reorderable would leave
|
||||
tabs reordered in the tab list popup. [@Xipiryon]
|
||||
- Columns: Fix inverted ClipRect being passed to renderer when using certain primitives inside of
|
||||
a fully clipped column. (#3475) [@szreder]
|
||||
- Popups, Tooltips: Fix edge cases issues with positionning popups and tooltips when they are larger than
|
||||
viewport on either or both axises. [@Rokups]
|
||||
- Fonts: AddFontDefault() adjust its vertical offset based on floor(size/13) instead of always +1.
|
||||
- Metrics: Various tweaks, listing windows front-to-back, greying inactive items when possible.
|
||||
- Demo: Add simple InputText() callbacks demo (aside from the more elaborate ones in 'Examples->Console').
|
||||
- Backends: OpenGL3: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 contexts which have
|
||||
the defines set by a loader. (#3467, #1985) [@jjwebb]
|
||||
- Backends: Vulkan: Some internal refactor aimed at allowing multi-viewport feature to create their
|
||||
own render pass. (#3455, #3459) [@FunMiles]
|
||||
- Backends: DX12: Clarified that imgui_impl_dx12 can be compiled on 32-bit systems by redefining
|
||||
the ImTextureID to be 64-bit (e.g. '#define ImTextureID ImU64' in imconfig.h). (#301)
|
||||
- Backends: DX12: Fix debug layer warning when scissor rect is zero-sized. (#3472, #3462) [@StoneWolf]
|
||||
- Examples: Vulkan: Reworked buffer resize handling, fix for Linux/X11. (#3390, #2626) [@RoryO]
|
||||
- Examples: Vulkan: Switch validation layer to use "VK_LAYER_KHRONOS_validation" instead of
|
||||
"VK_LAYER_LUNARG_standard_validation" which is deprecated (#3459) [@FunMiles]
|
||||
- Examples: DX12: Enable breaking on any warning/error when debug interface is enabled.
|
||||
- Examples: DX12: Added '#define ImTextureID ImU64' in project and build files to also allow building
|
||||
on 32-bit systems. Added project to default Visual Studio solution file. (#301)
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
@ -252,6 +292,7 @@ Breaking Changes:
|
||||
note that this is a Beta api and will likely be reworked in order to support multi-DPI across
|
||||
multiple monitors.
|
||||
- Renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete).
|
||||
[NOTE: THIS WAS REVERTED IN 1.79]
|
||||
- Removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor
|
||||
of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
|
||||
Kept inline redirection function (will obsolete).
|
||||
@ -1535,7 +1576,7 @@ Breaking Changes:
|
||||
- removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
|
||||
- Renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
|
||||
- Fonts: Moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
|
||||
- Fonts: changed ImFont::DisplayOffset.y to defaults to 0 instead of +1. Fixed vertical rounding of Ascent/Descent to match TrueType renderer.
|
||||
- Fonts: Changed ImFont::DisplayOffset.y to defaults to 0 instead of +1. Fixed vertical rounding of Ascent/Descent to match TrueType renderer.
|
||||
If you were adding or subtracting (not assigning) to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. (#1619)
|
||||
- BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
|
||||
- Obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
|
||||
|
@ -142,13 +142,6 @@ ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
|
||||
![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/code_sample_02_jp.png)
|
||||
<br>_(settings: Dark style (left), Light style (right) / Font: NotoSansCJKjp-Medium, 20px / Rounding: 5)_
|
||||
|
||||
|
||||
**Offset font vertically by altering the `io.Font->DisplayOffset` value:**
|
||||
```cpp
|
||||
ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels);
|
||||
font->DisplayOffset.y = 1; // Render 1 pixel down
|
||||
```
|
||||
|
||||
**Font Atlas too large?**
|
||||
|
||||
- If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. The typical result of failing to upload a texture is if every glyphs appears as white rectangles.
|
||||
@ -337,13 +330,13 @@ DroidSans.ttf
|
||||
ProggyClean.ttf
|
||||
Copyright (c) 2004, 2005 Tristan Grimmer
|
||||
MIT License
|
||||
recommended loading setting: Size = 13.0, DisplayOffset.Y = +1
|
||||
recommended loading setting: Size = 13.0, GlyphOffset.y = +1
|
||||
http://www.proggyfonts.net/
|
||||
|
||||
ProggyTiny.ttf
|
||||
Copyright (c) 2004, 2005 Tristan Grimmer
|
||||
MIT License
|
||||
recommended loading setting: Size = 10.0, DisplayOffset.Y = +1
|
||||
recommended loading setting: Size = 10.0, GlyphOffset.y = +1
|
||||
http://www.proggyfonts.net/
|
||||
|
||||
Karla-Regular.ttf
|
||||
|
@ -98,7 +98,7 @@ Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcas
|
||||
![screenshot demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png)
|
||||
|
||||
You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here:
|
||||
- [imgui-demo-binaries-20200412.zip](http://www.dearimgui.org/binaries/imgui-demo-binaries-20200412.zip) (Windows, 1.76, built 2020/04/12, master branch) or [older demo binaries](http://www.dearimgui.org/binaries).
|
||||
- [imgui-demo-binaries-20200918.zip](https://www.dearimgui.org/binaries/imgui-demo-binaries-20200918.zip) (Windows, 1.78 WIP, built 2020/09/18, master branch) or [older demo binaries](https://www.dearimgui.org/binaries).
|
||||
|
||||
The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at different scale, and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.org/faq)).
|
||||
|
||||
@ -114,7 +114,7 @@ Officially maintained bindings (in repository):
|
||||
- Frameworks: Emscripten, Allegro5, Marmalade.
|
||||
|
||||
Third-party bindings (see [Bindings](https://github.com/ocornut/imgui/wiki/Bindings/) page):
|
||||
- Languages: C, C# and: Beef, ChaiScript, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lua, Odin, Pascal, PureBasic, Python, Ruby, Rust, Swift...
|
||||
- Languages: C, C# and: Beef, ChaiScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lua, Odin, Pascal, PureBasic, Python, Ruby, Rust, Swift...
|
||||
- Frameworks: AGS/Adventure Game Studio, Amethyst, bsf, Cinder, Cocos2d-x, Diligent Engine, Flexium, GML/Game Maker Studio2, Godot, GTK3+OpenGL3, Irrlicht Engine, LÖVE+LUA, Magnum, NanoRT, nCine, Nim Game Lib, Ogre, openFrameworks, OSG/OpenSceneGraph, Orx, Photoshop, px_render, Qt/QtDirect3D, SFML, Sokol, Unity, Unreal Engine 4, vtk, Win32 GDI, WxWidgets.
|
||||
- Note that C bindings ([cimgui](https://github.com/cimgui/cimgui)) are auto-generated, you can use its json/lua output to generate bindings for other languages.
|
||||
|
||||
|
@ -247,7 +247,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
|
||||
- popups/modals: although it is sometimes convenient that popups/modals lifetime is owned by imgui, we could also a bool-owned-by-user api as long as Begin() return value testing is enforced.
|
||||
|
||||
- tooltip: drag and drop with tooltip near monitor edges lose/changes its last direction instead of locking one. The drag and drop tooltip should always follow without changing direction.
|
||||
- tooltip: tooltip that doesn't fit in entire screen seems to lose their "last preferred direction" and may teleport when moving mouse.
|
||||
- tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic.
|
||||
- tooltip: tooltips with delay timers? or general timer policy? (instantaneous vs timed): IsItemHovered() with timer + implicit aabb-id for items with no ID. (#1485)
|
||||
- tooltip: drag tooltip hovering over source widget with IsItemHovered/SetTooltip flickers.
|
||||
|
@ -1,4 +1,5 @@
|
||||
@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler.
|
||||
@REM Important: to build on 32-bit systems, the DX12 back-ends needs '#define ImTextureID ImU64', so we pass it here.
|
||||
mkdir Debug
|
||||
cl /nologo /Zi /MD /I .. /I ..\.. /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /D UNICODE /D _UNICODE *.cpp ..\imgui_impl_dx12.cpp ..\imgui_impl_win32.cpp ..\..\imgui*.cpp /FeDebug/example_win32_directx12.exe /FoDebug/ /link d3d12.lib d3dcompiler.lib dxgi.lib
|
||||
cl /nologo /Zi /MD /I .. /I ..\.. /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /D ImTextureID=ImU64 /D UNICODE /D _UNICODE *.cpp ..\imgui_impl_dx12.cpp ..\imgui_impl_win32.cpp ..\..\imgui*.cpp /FeDebug/example_win32_directx12.exe /FoDebug/ /link d3d12.lib d3dcompiler.lib dxgi.lib
|
||||
|
||||
|
@ -87,6 +87,7 @@
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -100,6 +101,7 @@
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -115,6 +117,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -132,6 +135,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -260,19 +260,32 @@ bool CreateDeviceD3D(HWND hWnd)
|
||||
sd.Stereo = FALSE;
|
||||
}
|
||||
|
||||
// [DEBUG] Enable debug interface
|
||||
#ifdef DX12_ENABLE_DEBUG_LAYER
|
||||
ID3D12Debug* pdx12Debug = NULL;
|
||||
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pdx12Debug))))
|
||||
{
|
||||
pdx12Debug->EnableDebugLayer();
|
||||
pdx12Debug->Release();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create device
|
||||
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||
if (D3D12CreateDevice(NULL, featureLevel, IID_PPV_ARGS(&g_pd3dDevice)) != S_OK)
|
||||
return false;
|
||||
|
||||
// [DEBUG] Setup debug interface to break on any warnings/errors
|
||||
#ifdef DX12_ENABLE_DEBUG_LAYER
|
||||
if (pdx12Debug != NULL)
|
||||
{
|
||||
ID3D12InfoQueue* pInfoQueue = NULL;
|
||||
g_pd3dDevice->QueryInterface(IID_PPV_ARGS(&pInfoQueue));
|
||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
|
||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
|
||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true);
|
||||
pInfoQueue->Release();
|
||||
pdx12Debug->Release();
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
|
@ -6,8 +6,10 @@
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// Missing features, issues:
|
||||
// [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301
|
||||
|
||||
// Important: to compile on 32-bit systems, this back-end requires code to be compiled with '#define ImTextureID ImU64'.
|
||||
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||
// This define is done in the example .vcxproj file and need to be replicated in your app (by e.g. editing imconfig.h)
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
@ -16,6 +18,8 @@
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
|
||||
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
|
||||
// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
|
||||
// 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
@ -316,11 +320,14 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||
{
|
||||
// Apply Scissor, Bind texture, Draw
|
||||
const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
|
||||
if (r.right > r.left && r.bottom > r.top)
|
||||
{
|
||||
ctx->SetGraphicsRootDescriptorTable(1, *(D3D12_GPU_DESCRIPTOR_HANDLE*)&pcmd->TextureId);
|
||||
ctx->RSSetScissorRects(1, &r);
|
||||
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
@ -5,8 +5,10 @@
|
||||
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// Missing features, issues:
|
||||
// [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301
|
||||
|
||||
// Important: to compile on 32-bit systems, this back-end requires code to be compiled with '#define ImTextureID ImU64'.
|
||||
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||
// This define is done in the example .vcxproj file and need to be replicated in your app (by e.g. editing imconfig.h)
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
|
@ -15,6 +15,7 @@
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||
@ -83,7 +84,6 @@
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <GLES2/gl2.h>
|
||||
@ -126,10 +126,13 @@ using namespace gl;
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0
|
||||
#else
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.3+ has glBindSampler()
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
@ -161,7 +164,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
// Setup back-end capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (g_GlVersion >= 320)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
@ -274,7 +277,9 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
|
||||
glUseProgram(g_ShaderHandle);
|
||||
glUniform1i(g_AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
#ifdef GL_SAMPLER_BINDING
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (g_GlVersion >= 330)
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||
#endif
|
||||
|
||||
@ -310,8 +315,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||
#ifdef GL_SAMPLER_BINDING
|
||||
GLuint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
@ -383,7 +388,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (g_GlVersion >= 320)
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
|
||||
else
|
||||
@ -402,7 +407,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef GL_SAMPLER_BINDING
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (g_GlVersion >= 330)
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
|
@ -3,10 +3,11 @@
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h)
|
||||
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
|
||||
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include
|
||||
// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
|
||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
|
||||
//-----------------------------------------------------------------------------
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
80
imgui.cpp
80
imgui.cpp
@ -382,7 +382,9 @@ CODE
|
||||
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
|
||||
- 2020/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
|
||||
|
||||
|
||||
- 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.
|
||||
- 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
|
||||
- 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. It was also getting in the way of better font scaling, so let's get rid of it now!
|
||||
- 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
|
||||
replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
|
||||
worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
|
||||
@ -394,7 +396,7 @@ CODE
|
||||
for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
|
||||
- obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
|
||||
- 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
|
||||
- 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete).
|
||||
- 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]
|
||||
- 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
|
||||
- 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
|
||||
- 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
|
||||
@ -7417,6 +7419,20 @@ void ImGui::PushOverrideID(ImGuiID id)
|
||||
window->IDStack.push_back(id);
|
||||
}
|
||||
|
||||
// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call
|
||||
// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level.
|
||||
// for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more)
|
||||
ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
|
||||
{
|
||||
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
|
||||
ImGui::KeepAliveID(id);
|
||||
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
||||
ImGuiContext& g = *GImGui;
|
||||
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
void ImGui::PopID()
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
@ -8642,8 +8658,9 @@ void ImGui::EndPopup()
|
||||
g.WithinEndChild = false;
|
||||
}
|
||||
|
||||
// Open a popup if mouse button is released over the item
|
||||
bool ImGui::OpenPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
|
||||
// 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)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
|
||||
@ -8652,16 +8669,14 @@ bool ImGui::OpenPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags
|
||||
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // 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);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is a helper to handle the simplest case of associating one named popup to one given widget.
|
||||
// - You can pass a NULL str_id to use the identifier of the last item.
|
||||
// - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
|
||||
// - This is essentially the same as calling OpenPopupContextItem() + BeginPopup() but written to avoid
|
||||
// computing the ID twice because BeginPopupContextXXX functions are called very frequently.
|
||||
// - This is essentially the same as calling OpenPopupOnItemClick() + BeginPopup() but written to avoid
|
||||
// computing the ID twice because BeginPopupContextXXX functions may be called very frequently.
|
||||
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
@ -8733,26 +8748,47 @@ ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& s
|
||||
}
|
||||
}
|
||||
|
||||
// Default popup policy
|
||||
// Tooltip and Default popup policy
|
||||
// (Always first try the direction we used on the last frame, if any)
|
||||
if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default)
|
||||
{
|
||||
const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
|
||||
for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
|
||||
{
|
||||
const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
|
||||
if (n != -1 && dir == *last_dir) // Already tried this direction?
|
||||
continue;
|
||||
float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
|
||||
float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
|
||||
if (avail_w < size.x || avail_h < size.y)
|
||||
|
||||
const float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
|
||||
const float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
|
||||
|
||||
// If there not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width)
|
||||
if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))
|
||||
continue;
|
||||
if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))
|
||||
continue;
|
||||
|
||||
ImVec2 pos;
|
||||
pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
|
||||
pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
|
||||
|
||||
// Clamp top-left corner of popup
|
||||
pos.x = ImMax(pos.x, r_outer.Min.x);
|
||||
pos.y = ImMax(pos.y, r_outer.Min.y);
|
||||
|
||||
*last_dir = dir;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback, try to keep within display
|
||||
// Fallback when not enough room:
|
||||
*last_dir = ImGuiDir_None;
|
||||
|
||||
// For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
|
||||
if (policy == ImGuiPopupPositionPolicy_Tooltip)
|
||||
return ref_pos + ImVec2(2, 2);
|
||||
|
||||
// Otherwise try to keep within display
|
||||
ImVec2 pos = ref_pos;
|
||||
pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
|
||||
pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
|
||||
@ -8797,13 +8833,13 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
||||
r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field
|
||||
else
|
||||
r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX);
|
||||
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
|
||||
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
|
||||
}
|
||||
if (window->Flags & ImGuiWindowFlags_Popup)
|
||||
{
|
||||
ImRect r_outer = GetWindowAllowedExtentRect(window);
|
||||
ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
|
||||
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
|
||||
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
|
||||
}
|
||||
if (window->Flags & ImGuiWindowFlags_Tooltip)
|
||||
{
|
||||
@ -8816,10 +8852,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
|
||||
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
|
||||
else
|
||||
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
|
||||
ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
|
||||
if (window->AutoPosLastDirection == ImGuiDir_None)
|
||||
pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
|
||||
return pos;
|
||||
return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
|
||||
}
|
||||
IM_ASSERT(0);
|
||||
return window->Pos;
|
||||
@ -15774,6 +15807,13 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
||||
bool open = ImGui::TreeNode(tab_bar, "%s", buf);
|
||||
if (!is_active) { PopStyleColor(); }
|
||||
if (is_active && ImGui::IsItemHovered())
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetForegroundDrawList();
|
||||
draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
|
||||
draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
|
||||
draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
|
||||
}
|
||||
if (open)
|
||||
{
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
@ -15782,7 +15822,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
ImGui::PushID(tab);
|
||||
if (ImGui::SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
|
||||
if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine();
|
||||
ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "");
|
||||
ImGui::Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
|
28
imgui.h
28
imgui.h
@ -632,13 +632,13 @@ namespace ImGui
|
||||
// - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options).
|
||||
// - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup().
|
||||
IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!).
|
||||
IMGUI_API bool OpenPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)
|
||||
IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)
|
||||
IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into.
|
||||
// Popups: open+begin combined functions helpers
|
||||
// - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking.
|
||||
// - They are convenient to easily create context menus, hence the name.
|
||||
// - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future.
|
||||
// - We exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter. Passing a mouse button to ImGuiPopupFlags is guaranteed to be legal.
|
||||
// - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight.
|
||||
IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
|
||||
IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window.
|
||||
IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows).
|
||||
@ -668,6 +668,7 @@ namespace ImGui
|
||||
IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true!
|
||||
IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected.
|
||||
IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true!
|
||||
IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar.
|
||||
IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
|
||||
|
||||
// Docking
|
||||
@ -931,13 +932,15 @@ enum ImGuiTreeNodeFlags_
|
||||
// small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags.
|
||||
// It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags.
|
||||
// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0.
|
||||
// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter
|
||||
// and want to another another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag.
|
||||
// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later).
|
||||
enum ImGuiPopupFlags_
|
||||
{
|
||||
ImGuiPopupFlags_None = 0,
|
||||
ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranted to always be == 0 (same as ImGuiMouseButton_Left)
|
||||
ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranted to always be == 1 (same as ImGuiMouseButton_Right)
|
||||
ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranted to always be == 2 (same as ImGuiMouseButton_Middle)
|
||||
ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left)
|
||||
ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right)
|
||||
ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle)
|
||||
ImGuiPopupFlags_MouseButtonMask_ = 0x1F,
|
||||
ImGuiPopupFlags_MouseButtonDefault_ = 1,
|
||||
ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack
|
||||
@ -996,7 +999,10 @@ enum ImGuiTabItemFlags_
|
||||
ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem()
|
||||
ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
|
||||
ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()
|
||||
ImGuiTabItemFlags_NoTooltip = 1 << 4 // Disable tooltip for the given tab
|
||||
ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab
|
||||
ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab
|
||||
ImGuiTabItemFlags_Leading = 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button)
|
||||
ImGuiTabItemFlags_Trailing = 1 << 7 // Enforce the tab position to the right of the tab bar (before the scrolling buttons)
|
||||
};
|
||||
|
||||
// Flags for ImGui::IsWindowFocused()
|
||||
@ -1815,7 +1821,9 @@ struct ImGuiPayload
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
namespace ImGui
|
||||
{
|
||||
// OBSOLETED in 1.78 (from August 2020)
|
||||
// OBSOLETED in 1.79 (from August 2020)
|
||||
static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry!
|
||||
// OBSOLETED in 1.78 (from June 2020)
|
||||
// Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags.
|
||||
// For shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
|
||||
IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power);
|
||||
@ -1831,9 +1839,8 @@ namespace ImGui
|
||||
static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); }
|
||||
static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); }
|
||||
// OBSOLETED in 1.77 (from June 2020)
|
||||
static inline bool OpenPopupOnItemClick(const char* str_id = NULL, ImGuiMouseButton mb = 1) { return OpenPopupContextItem(str_id, mb); } // Passing a mouse button to ImGuiPopupFlags is legal
|
||||
static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); }
|
||||
// OBSOLETED in 1.72 (from July 2019)
|
||||
// OBSOLETED in 1.72 (from April 2019)
|
||||
static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); }
|
||||
// OBSOLETED in 1.71 (from June 2019)
|
||||
static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }
|
||||
@ -2509,11 +2516,10 @@ struct ImFont
|
||||
float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX
|
||||
float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading)
|
||||
|
||||
// Members: Hot ~36/48 bytes (for CalcTextSize + render loop)
|
||||
// Members: Hot ~28/40 bytes (for CalcTextSize + render loop)
|
||||
ImVector<ImWchar> IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point.
|
||||
ImVector<ImFontGlyph> Glyphs; // 12-16 // out // // All glyphs.
|
||||
const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar)
|
||||
ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels
|
||||
|
||||
// Members: Cold ~32/40 bytes
|
||||
ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into
|
||||
|
@ -909,7 +909,7 @@ static void ShowDemoWindowWidgets()
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
|
||||
if (n == 0)
|
||||
ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
|
||||
if (n == 1)
|
||||
else
|
||||
ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
|
||||
|
||||
// Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
|
||||
@ -1008,7 +1008,7 @@ static void ShowDemoWindowWidgets()
|
||||
int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding)
|
||||
ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
|
||||
ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
|
||||
ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32 / my_tex_h); // UV coordinates for (32,32) in our texture
|
||||
ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture
|
||||
ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
|
||||
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
|
||||
if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col))
|
||||
@ -1037,7 +1037,7 @@ static void ShowDemoWindowWidgets()
|
||||
// stored in the object itself, etc.)
|
||||
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
|
||||
static int item_current_idx = 0; // Here our selection data is an index.
|
||||
const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically could be anything)(
|
||||
const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically it could be anything)
|
||||
if (ImGui::BeginCombo("combo 1", combo_label, flags))
|
||||
{
|
||||
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
|
||||
@ -2412,6 +2412,72 @@ static void ShowDemoWindowLayout()
|
||||
ImGui::Separator();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
|
||||
{
|
||||
static ImVector<int> active_tabs;
|
||||
static int next_tab_id = 0;
|
||||
if (next_tab_id == 0) // Initialize with some default tabs
|
||||
for (int i = 0; i < 3; i++)
|
||||
active_tabs.push_back(next_tab_id++);
|
||||
|
||||
// TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
|
||||
// (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
|
||||
// but they tend to make more sense together)
|
||||
static bool show_leading_button = true;
|
||||
static bool show_trailing_button = true;
|
||||
ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
|
||||
ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
|
||||
|
||||
// Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
|
||||
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
|
||||
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
|
||||
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
|
||||
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
|
||||
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
|
||||
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
|
||||
|
||||
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
|
||||
{
|
||||
// Demo a Leading TabItemButton(): click the "?" button to open a menu
|
||||
if (show_leading_button)
|
||||
if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
|
||||
ImGui::OpenPopup("MyHelpMenu");
|
||||
if (ImGui::BeginPopup("MyHelpMenu"))
|
||||
{
|
||||
ImGui::Selectable("Hello!");
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+")
|
||||
// Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
|
||||
if (show_trailing_button)
|
||||
if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
|
||||
active_tabs.push_back(next_tab_id++); // Add new tab
|
||||
|
||||
// Submit our regular tabs
|
||||
for (int n = 0; n < active_tabs.Size; )
|
||||
{
|
||||
bool open = true;
|
||||
char name[16];
|
||||
snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
|
||||
if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
|
||||
{
|
||||
ImGui::Text("This is the %s tab!", name);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (!open)
|
||||
active_tabs.erase(active_tabs.Data + n);
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
@ -3035,11 +3101,11 @@ static void ShowDemoWindowPopups()
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// We can also use OpenPopupContextItem() which is the same as BeginPopupContextItem() but without the
|
||||
// We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the
|
||||
// Begin() call. So here we will make it that clicking on the text field with the right mouse button (1)
|
||||
// will toggle the visibility of the popup above.
|
||||
ImGui::Text("(You can also right-click me to open the same popup as above.)");
|
||||
ImGui::OpenPopupContextItem("item context menu", 1);
|
||||
ImGui::OpenPopupOnItemClick("item context menu", 1);
|
||||
|
||||
// When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem().
|
||||
// BeginPopupContextItem() will use the last item ID as the popup ID.
|
||||
@ -3797,7 +3863,6 @@ static void NodeFont(ImFont* font)
|
||||
"You may oversample them to get some flexibility with scaling. "
|
||||
"You can also render at multiple sizes and select which one to use at runtime.\n\n"
|
||||
"(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
|
||||
ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
|
||||
ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
|
||||
ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar);
|
||||
ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar);
|
||||
@ -3806,8 +3871,8 @@ static void NodeFont(ImFont* font)
|
||||
for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
|
||||
if (font->ConfigData)
|
||||
if (const ImFontConfig* cfg = &font->ConfigData[config_i])
|
||||
ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d",
|
||||
config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
|
||||
ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
|
||||
config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
|
||||
if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
|
||||
{
|
||||
// Display all glyphs of the fonts in separate pages of 256 characters
|
||||
@ -5024,8 +5089,10 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
|
||||
const float DISTANCE = 10.0f;
|
||||
static int corner = 0;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
|
||||
if (corner != -1)
|
||||
{
|
||||
window_flags |= ImGuiWindowFlags_NoMove;
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImVec2 work_area_pos = viewport->GetWorkPos(); // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
|
||||
ImVec2 work_area_size = viewport->GetWorkSize();
|
||||
@ -5035,9 +5102,6 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
}
|
||||
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
|
||||
if (corner != -1)
|
||||
window_flags |= ImGuiWindowFlags_NoMove;
|
||||
if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
|
||||
{
|
||||
ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
|
||||
@ -5269,7 +5333,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
// Context menu (under default mouse threshold)
|
||||
ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
|
||||
if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
|
||||
ImGui::OpenPopupContextItem("context");
|
||||
ImGui::OpenPopupOnItemClick("context");
|
||||
if (ImGui::BeginPopup("context"))
|
||||
{
|
||||
if (adding_line)
|
||||
|
@ -345,7 +345,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ImDrawList
|
||||
// [SECTION] ImDrawList
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ImDrawListSharedData::ImDrawListSharedData()
|
||||
@ -1411,7 +1411,7 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_mi
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ImDrawListSplitter
|
||||
// [SECTION] ImDrawListSplitter
|
||||
//-----------------------------------------------------------------------------
|
||||
// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1897,11 +1897,11 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
|
||||
if (font_cfg.Name[0] == '\0')
|
||||
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
|
||||
font_cfg.EllipsisChar = (ImWchar)0x0085;
|
||||
font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units
|
||||
|
||||
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
|
||||
const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
|
||||
ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges);
|
||||
font->DisplayOffset.y = 1.0f;
|
||||
return font;
|
||||
}
|
||||
|
||||
@ -2774,7 +2774,6 @@ ImFont::ImFont()
|
||||
FallbackAdvanceX = 0.0f;
|
||||
FallbackChar = (ImWchar)'?';
|
||||
EllipsisChar = (ImWchar)-1;
|
||||
DisplayOffset = ImVec2(0.0f, 0.0f);
|
||||
FallbackGlyph = NULL;
|
||||
ContainerAtlas = NULL;
|
||||
ConfigData = NULL;
|
||||
@ -3169,8 +3168,8 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||
if (!glyph || !glyph->Visible)
|
||||
return;
|
||||
float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
|
||||
pos.x = IM_FLOOR(pos.x + DisplayOffset.x);
|
||||
pos.y = IM_FLOOR(pos.y + DisplayOffset.y);
|
||||
pos.x = IM_FLOOR(pos.x);
|
||||
pos.y = IM_FLOOR(pos.y);
|
||||
draw_list->PrimReserve(6, 4);
|
||||
draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
|
||||
}
|
||||
@ -3181,8 +3180,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||
|
||||
// Align to be pixel perfect
|
||||
pos.x = IM_FLOOR(pos.x + DisplayOffset.x);
|
||||
pos.y = IM_FLOOR(pos.y + DisplayOffset.y);
|
||||
pos.x = IM_FLOOR(pos.x);
|
||||
pos.y = IM_FLOOR(pos.y);
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
if (y > clip_rect.w)
|
||||
|
@ -789,7 +789,8 @@ enum ImGuiNavLayer
|
||||
enum ImGuiPopupPositionPolicy
|
||||
{
|
||||
ImGuiPopupPositionPolicy_Default,
|
||||
ImGuiPopupPositionPolicy_ComboBox
|
||||
ImGuiPopupPositionPolicy_ComboBox,
|
||||
ImGuiPopupPositionPolicy_Tooltip
|
||||
};
|
||||
|
||||
struct ImGuiDataTypeTempStorage
|
||||
@ -1906,8 +1907,9 @@ enum ImGuiTabBarFlagsPrivate_
|
||||
enum ImGuiTabItemFlagsPrivate_
|
||||
{
|
||||
ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout)
|
||||
ImGuiTabItemFlags_Unsorted = 1 << 21, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
|
||||
ImGuiTabItemFlags_Preview = 1 << 22 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar)
|
||||
ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button
|
||||
ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window.
|
||||
ImGuiTabItemFlags_Preview = 1 << 23 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar)
|
||||
};
|
||||
|
||||
// Storage for one active tab item (sizeof() 32~40 bytes)
|
||||
@ -1920,12 +1922,13 @@ struct ImGuiTabItem
|
||||
int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
|
||||
float Offset; // Position relative to beginning of tab
|
||||
float Width; // Width currently displayed
|
||||
float ContentWidth; // Width of actual contents, stored during BeginTabItem() call
|
||||
float ContentWidth; // Width of label, stored during BeginTabItem() call
|
||||
ImS16 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
|
||||
ImS8 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable
|
||||
ImS8 IndexDuringLayout; // Index only used during TabBarLayout()
|
||||
bool WantClose; // Marked as closed by SetTabItemClosed()
|
||||
|
||||
ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; WantClose = false; }
|
||||
ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; IndexDuringLayout = -1; WantClose = false; }
|
||||
};
|
||||
|
||||
// Storage for a tab bar (sizeof() 92~96 bytes)
|
||||
@ -1942,17 +1945,19 @@ struct ImGuiTabBar
|
||||
float LastTabContentHeight; // Record the height of contents submitted below the tab bar
|
||||
float WidthAllTabs; // Actual width of all tabs (locked during layout)
|
||||
float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped
|
||||
float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set.
|
||||
float ScrollingAnim;
|
||||
float ScrollingTarget;
|
||||
float ScrollingTargetDistToVisibility;
|
||||
float ScrollingSpeed;
|
||||
float ScrollingRectMinX;
|
||||
float ScrollingRectMaxX;
|
||||
ImGuiTabBarFlags Flags;
|
||||
ImGuiID ReorderRequestTabId;
|
||||
ImS8 ReorderRequestDir;
|
||||
ImS8 TabsActiveCount; // Number of tabs submitted this frame.
|
||||
bool WantLayout;
|
||||
bool VisibleTabWasSubmitted;
|
||||
bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame
|
||||
short LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem()
|
||||
ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar()
|
||||
ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer.
|
||||
@ -2061,6 +2066,7 @@ namespace ImGui
|
||||
IMGUI_API void KeepAliveID(ImGuiID id);
|
||||
IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function.
|
||||
IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes)
|
||||
IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed);
|
||||
|
||||
// Basic Helpers for widget code
|
||||
IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f);
|
||||
@ -2094,7 +2100,7 @@ namespace ImGui
|
||||
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags);
|
||||
IMGUI_API ImGuiWindow* GetTopMostPopupModal();
|
||||
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 = ImGuiPopupPositionPolicy_Default);
|
||||
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
|
||||
|
||||
// Gamepad/Keyboard Navigation
|
||||
IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit);
|
||||
|
@ -274,6 +274,9 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
|
||||
void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
|
||||
{
|
||||
PushStyleColor(ImGuiCol_Text, col);
|
||||
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
|
||||
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
else
|
||||
TextV(fmt, args);
|
||||
PopStyleColor();
|
||||
}
|
||||
@ -288,7 +291,11 @@ void ImGui::TextDisabled(const char* fmt, ...)
|
||||
|
||||
void ImGui::TextDisabledV(const char* fmt, va_list args)
|
||||
{
|
||||
PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]);
|
||||
ImGuiContext& g = *GImGui;
|
||||
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
|
||||
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
|
||||
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
else
|
||||
TextV(fmt, args);
|
||||
PopStyleColor();
|
||||
}
|
||||
@ -303,10 +310,13 @@ void ImGui::TextWrapped(const char* fmt, ...)
|
||||
|
||||
void ImGui::TextWrappedV(const char* fmt, va_list args)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
bool need_backup = (window->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
|
||||
ImGuiContext& g = *GImGui;
|
||||
bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
|
||||
if (need_backup)
|
||||
PushTextWrapPos(0.0f);
|
||||
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
|
||||
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
else
|
||||
TextV(fmt, args);
|
||||
if (need_backup)
|
||||
PopTextWrapPos();
|
||||
@ -1423,10 +1433,12 @@ static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)
|
||||
}
|
||||
|
||||
// Shrink excess width from a set of item, by removing width from the larger items first.
|
||||
// Set items Width to -1.0f to disable shrinking this item.
|
||||
void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
if (items[0].Width >= 0.0f)
|
||||
items[0].Width = ImMax(items[0].Width - width_excess, 1.0f);
|
||||
return;
|
||||
}
|
||||
@ -1436,7 +1448,9 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
||||
{
|
||||
while (count_same_width < count && items[0].Width <= items[count_same_width].Width)
|
||||
count_same_width++;
|
||||
float max_width_to_remove_per_item = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
|
||||
float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
|
||||
if (max_width_to_remove_per_item <= 0.0f)
|
||||
break;
|
||||
float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item);
|
||||
for (int item_n = 0; item_n < count_same_width; item_n++)
|
||||
items[item_n].Width -= width_to_remove_per_item;
|
||||
@ -3587,6 +3601,8 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im
|
||||
#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo
|
||||
#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word
|
||||
#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word
|
||||
#define STB_TEXTEDIT_K_PGUP 0x20000E // keyboard input to move cursor up a page
|
||||
#define STB_TEXTEDIT_K_PGDOWN 0x20000F // keyboard input to move cursor down a page
|
||||
#define STB_TEXTEDIT_K_SHIFT 0x400000
|
||||
|
||||
#define STB_TEXTEDIT_IMPLEMENTATION
|
||||
@ -3853,6 +3869,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
bool clear_active_id = false;
|
||||
bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
|
||||
|
||||
float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX;
|
||||
|
||||
const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start);
|
||||
const bool init_state = (init_make_active || user_scroll_active);
|
||||
if (init_state && g.ActiveId != id)
|
||||
@ -3913,7 +3931,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);
|
||||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End);
|
||||
if (is_multiline)
|
||||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); // FIXME-NAV: Page up/down actually not supported yet by widget, but claim them ahead.
|
||||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown);
|
||||
if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character.
|
||||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab);
|
||||
}
|
||||
@ -3955,7 +3973,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
ImFont* password_font = &g.InputTextPasswordFont;
|
||||
password_font->FontSize = g.Font->FontSize;
|
||||
password_font->Scale = g.Font->Scale;
|
||||
password_font->DisplayOffset = g.Font->DisplayOffset;
|
||||
password_font->Ascent = g.Font->Ascent;
|
||||
password_font->Descent = g.Font->Descent;
|
||||
password_font->ContainerAtlas = g.Font->ContainerAtlas;
|
||||
@ -4053,6 +4070,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
IM_ASSERT(state != NULL);
|
||||
IM_ASSERT(io.KeyMods == GetMergedKeyModFlags() && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); // We rarely do this check, but if anything let's do it here.
|
||||
|
||||
const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1);
|
||||
state->Stb.row_count_per_page = row_count_per_page;
|
||||
|
||||
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
|
||||
const bool is_osx = io.ConfigMacOSXBehaviors;
|
||||
const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyModFlags_Super | ImGuiKeyModFlags_Shift));
|
||||
@ -4072,6 +4092,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; }
|
||||
else if (IsKeyPressedMap(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; }
|
||||
else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
|
||||
else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
|
||||
@ -4441,12 +4463,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (is_multiline)
|
||||
{
|
||||
// Test if cursor is vertically visible
|
||||
float scroll_y = draw_window->Scroll.y;
|
||||
const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f);
|
||||
if (cursor_offset.y - g.FontSize < scroll_y)
|
||||
scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
|
||||
else if (cursor_offset.y - inner_size.y >= scroll_y)
|
||||
scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;
|
||||
const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f);
|
||||
scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y);
|
||||
draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
|
||||
draw_window->Scroll.y = scroll_y;
|
||||
@ -4692,7 +4713,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
|
||||
}
|
||||
if (!(flags & ImGuiColorEditFlags_NoOptions))
|
||||
OpenPopupContextItem("context");
|
||||
OpenPopupOnItemClick("context");
|
||||
}
|
||||
}
|
||||
else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
|
||||
@ -4717,7 +4738,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
|
||||
}
|
||||
if (!(flags & ImGuiColorEditFlags_NoOptions))
|
||||
OpenPopupContextItem("context");
|
||||
OpenPopupOnItemClick("context");
|
||||
}
|
||||
|
||||
ImGuiWindow* picker_active_window = NULL;
|
||||
@ -4738,7 +4759,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
}
|
||||
}
|
||||
if (!(flags & ImGuiColorEditFlags_NoOptions))
|
||||
OpenPopupContextItem("context");
|
||||
OpenPopupOnItemClick("context");
|
||||
|
||||
if (BeginPopup("picker"))
|
||||
{
|
||||
@ -4958,7 +4979,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
}
|
||||
}
|
||||
if (!(flags & ImGuiColorEditFlags_NoOptions))
|
||||
OpenPopupContextItem("context");
|
||||
OpenPopupOnItemClick("context");
|
||||
}
|
||||
else if (flags & ImGuiColorEditFlags_PickerHueBar)
|
||||
{
|
||||
@ -4971,7 +4992,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
value_changed = value_changed_sv = true;
|
||||
}
|
||||
if (!(flags & ImGuiColorEditFlags_NoOptions))
|
||||
OpenPopupContextItem("context");
|
||||
OpenPopupOnItemClick("context");
|
||||
|
||||
// Hue bar logic
|
||||
SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));
|
||||
@ -5891,7 +5912,8 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags
|
||||
float button_size = g.FontSize;
|
||||
float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size);
|
||||
float button_y = window->DC.LastItemRect.Min.y;
|
||||
if (CloseButton(window->GetID((void*)((intptr_t)id + 1)), ImVec2(button_x, button_y)))
|
||||
ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id);
|
||||
if (CloseButton(close_button_id, ImVec2(button_x, button_y)))
|
||||
*p_open = false;
|
||||
last_item_backup.Restore();
|
||||
}
|
||||
@ -6811,13 +6833,22 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
|
||||
// - TabBarTabListPopupButton() [Internal]
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiTabBarSection
|
||||
{
|
||||
int TabCount; // Number of tabs in this section.
|
||||
float Width; // Sum of width of tabs in this section (after shrinking down)
|
||||
float Spacing; // Horizontal spacing at the end of the section.
|
||||
|
||||
ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
static void TabBarLayout(ImGuiTabBar* tab_bar);
|
||||
static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label);
|
||||
static float TabBarCalcMaxTabWidth();
|
||||
static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);
|
||||
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
|
||||
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections);
|
||||
static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar);
|
||||
static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar);
|
||||
}
|
||||
@ -6828,16 +6859,28 @@ ImGuiTabBar::ImGuiTabBar()
|
||||
SelectedTabId = NextSelectedTabId = VisibleTabId = 0;
|
||||
CurrFrameVisible = PrevFrameVisible = -1;
|
||||
LastTabContentHeight = 0.0f;
|
||||
WidthAllTabs = WidthAllTabsIdeal = OffsetNextTab = 0.0f;
|
||||
WidthAllTabs = WidthAllTabsIdeal = 0.0f;
|
||||
ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f;
|
||||
ScrollingRectMinX = ScrollingRectMaxX = 0.0f;
|
||||
Flags = ImGuiTabBarFlags_None;
|
||||
ReorderRequestTabId = 0;
|
||||
ReorderRequestDir = 0;
|
||||
TabsActiveCount = 0;
|
||||
WantLayout = VisibleTabWasSubmitted = false;
|
||||
WantLayout = VisibleTabWasSubmitted = TabsAddedNew = false;
|
||||
LastTabItemIdx = -1;
|
||||
}
|
||||
|
||||
static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs)
|
||||
{
|
||||
const ImGuiTabItem* a = (const ImGuiTabItem*)lhs;
|
||||
const ImGuiTabItem* b = (const ImGuiTabItem*)rhs;
|
||||
const int a_section = (a->Flags & ImGuiTabItemFlags_Leading) ? 0 : (a->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
const int b_section = (b->Flags & ImGuiTabItemFlags_Leading) ? 0 : (b->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
if (a_section != b_section)
|
||||
return a_section - b_section;
|
||||
return (int)(a->IndexDuringLayout - b->IndexDuringLayout);
|
||||
}
|
||||
|
||||
static int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs)
|
||||
{
|
||||
const ImGuiTabItem* a = (const ImGuiTabItem*)lhs;
|
||||
@ -6894,10 +6937,11 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
|
||||
return true;
|
||||
}
|
||||
|
||||
// When toggling ImGuiTabBarFlags_Reorderable flag, ensure tabs are ordered based on their submission order.
|
||||
if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1)
|
||||
if ((flags & ImGuiTabBarFlags_DockNode) == 0)
|
||||
// Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable
|
||||
if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))
|
||||
if (tab_bar->Tabs.Size > 1 && (flags & ImGuiTabBarFlags_DockNode) == 0)
|
||||
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
|
||||
tab_bar->TabsAddedNew = false;
|
||||
|
||||
// Flags
|
||||
if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
|
||||
@ -6971,7 +7015,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
tab_bar->WantLayout = false;
|
||||
|
||||
// Garbage collect by compacting list
|
||||
// Detect if we need to sort out tab list (e.g. in rare case where a tab changed section)
|
||||
int tab_dst_n = 0;
|
||||
bool need_sort_by_section = false;
|
||||
ImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing
|
||||
for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n];
|
||||
@ -6985,11 +7032,32 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
}
|
||||
if (tab_dst_n != tab_src_n)
|
||||
tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n];
|
||||
|
||||
tab = &tab_bar->Tabs[tab_dst_n];
|
||||
tab->IndexDuringLayout = (ImS8)tab_dst_n;
|
||||
|
||||
// We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another)
|
||||
ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1];
|
||||
int curr_tab_section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
int prev_tab_section_n = (prev_tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (prev_tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
if (tab_dst_n > 0 && curr_tab_section_n == 0 && prev_tab_section_n != 0)
|
||||
need_sort_by_section = true;
|
||||
if (tab_dst_n > 0 && prev_tab_section_n == 2 && curr_tab_section_n != 2)
|
||||
need_sort_by_section = true;
|
||||
|
||||
sections[curr_tab_section_n].TabCount++;
|
||||
tab_dst_n++;
|
||||
}
|
||||
if (tab_bar->Tabs.Size != tab_dst_n)
|
||||
tab_bar->Tabs.resize(tab_dst_n);
|
||||
|
||||
if (need_sort_by_section)
|
||||
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerBySection);
|
||||
|
||||
// Calculate spacing between sections
|
||||
sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f;
|
||||
sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f;
|
||||
|
||||
// Setup next selected tab
|
||||
ImGuiID scroll_track_selected_tab_id = 0;
|
||||
if (tab_bar->NextSelectedTabId)
|
||||
@ -7011,23 +7079,29 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
// Tab List Popup (will alter tab_bar->BarRect and therefore the available width!)
|
||||
const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0;
|
||||
if (tab_list_popup_button)
|
||||
if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x!
|
||||
if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x!
|
||||
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
|
||||
|
||||
// Compute ideal widths
|
||||
// Leading/Trailing tabs will be shrink only if central one aren't visible anymore, so layout the shrink data as: leading, trailing, central
|
||||
// (whereas our tabs are stored as: leading, central, trailing)
|
||||
int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount };
|
||||
g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size);
|
||||
float width_total_contents = 0.0f;
|
||||
|
||||
// Compute ideal tabs widths + store them into shrink buffer
|
||||
ImGuiTabItem* most_recently_selected_tab = NULL;
|
||||
int curr_section_n = -1;
|
||||
bool found_selected_tab_id = false;
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible);
|
||||
|
||||
if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected)
|
||||
if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button))
|
||||
most_recently_selected_tab = tab;
|
||||
if (tab->ID == tab_bar->SelectedTabId)
|
||||
found_selected_tab_id = true;
|
||||
if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID)
|
||||
scroll_track_selected_tab_id = tab->ID;
|
||||
|
||||
// Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar.
|
||||
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
|
||||
@ -7036,56 +7110,87 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
const bool has_close_button = tab->Window ? tab->Window->HasCloseButton : ((tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0);
|
||||
tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x;
|
||||
|
||||
width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->ContentWidth;
|
||||
int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
ImGuiTabBarSection* section = §ions[section_n];
|
||||
section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f);
|
||||
curr_section_n = section_n;
|
||||
|
||||
// Store data so we can build an array sorted by width if we need to shrink tabs down
|
||||
g.ShrinkWidthBuffer[tab_n].Index = tab_n;
|
||||
g.ShrinkWidthBuffer[tab_n].Width = tab->ContentWidth;
|
||||
int shrink_buffer_index = shrink_buffer_indexes[section_n]++;
|
||||
g.ShrinkWidthBuffer[shrink_buffer_index].Index = tab_n;
|
||||
g.ShrinkWidthBuffer[shrink_buffer_index].Width = tab->ContentWidth;
|
||||
|
||||
IM_ASSERT(tab->ContentWidth > 0.0f);
|
||||
tab->Width = tab->ContentWidth;
|
||||
}
|
||||
|
||||
// Compute width
|
||||
const float initial_offset_x = 0.0f; // g.Style.ItemInnerSpacing.x;
|
||||
const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - initial_offset_x, 0.0f);
|
||||
float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f;
|
||||
if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown))
|
||||
// Compute total ideal width (used for e.g. auto-resizing a window)
|
||||
tab_bar->WidthAllTabsIdeal = 0.0f;
|
||||
for (int section_n = 0; section_n < 3; section_n++)
|
||||
tab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing;
|
||||
|
||||
// Horizontal scrolling buttons
|
||||
// (note that TabBarScrollButtons() will alter BarRect.Max.x)
|
||||
if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll))
|
||||
if (ImGuiTabItem* scroll_track_selected_tab = TabBarScrollingButtons(tab_bar))
|
||||
{
|
||||
// If we don't have enough room, resize down the largest tabs first
|
||||
ShrinkWidths(g.ShrinkWidthBuffer.Data, g.ShrinkWidthBuffer.Size, width_excess);
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width);
|
||||
scroll_track_selected_tab_id = scroll_track_selected_tab->ID;
|
||||
if (!(scroll_track_selected_tab->Flags & ImGuiTabItemFlags_Button))
|
||||
tab_bar->SelectedTabId = scroll_track_selected_tab_id;
|
||||
}
|
||||
|
||||
// Shrink widths if full tabs don't fit in their allocated space
|
||||
float section_0_w = sections[0].Width + sections[0].Spacing;
|
||||
float section_1_w = sections[1].Width + sections[1].Spacing;
|
||||
float section_2_w = sections[2].Width + sections[2].Spacing;
|
||||
bool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth();
|
||||
float width_excess;
|
||||
if (central_section_is_visible)
|
||||
width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f); // Excess used to shrink central section
|
||||
else
|
||||
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
|
||||
|
||||
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
|
||||
if (width_excess > 0.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
||||
{
|
||||
const float tab_max_width = TabBarCalcMaxTabWidth();
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
|
||||
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
|
||||
ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess);
|
||||
|
||||
// Apply shrunk values into tabs and sections
|
||||
for (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
tab->Width = ImMin(tab->ContentWidth, tab_max_width);
|
||||
IM_ASSERT(tab->Width > 0.0f);
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index];
|
||||
float shrinked_width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width);
|
||||
if (shrinked_width < 0.0f)
|
||||
continue;
|
||||
|
||||
int section_n = (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
|
||||
sections[section_n].Width -= (tab->Width - shrinked_width);
|
||||
tab->Width = shrinked_width;
|
||||
}
|
||||
}
|
||||
|
||||
// Layout all active tabs
|
||||
float offset_x = initial_offset_x;
|
||||
float offset_x_ideal = offset_x;
|
||||
tab_bar->OffsetNextTab = offset_x; // This is used by non-reorderable tab bar where the submission order is always honored.
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
int section_tab_index = 0;
|
||||
float tab_offset = 0.0f;
|
||||
tab_bar->WidthAllTabs = 0.0f;
|
||||
for (int section_n = 0; section_n < 3; section_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
tab->Offset = offset_x;
|
||||
if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID)
|
||||
scroll_track_selected_tab_id = tab->ID;
|
||||
offset_x += tab->Width + g.Style.ItemInnerSpacing.x;
|
||||
offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x;
|
||||
}
|
||||
tab_bar->WidthAllTabs = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
|
||||
tab_bar->WidthAllTabsIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f);
|
||||
ImGuiTabBarSection* section = §ions[section_n];
|
||||
if (section_n == 2)
|
||||
tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset);
|
||||
|
||||
// Horizontal scrolling buttons
|
||||
const bool scrolling_buttons = (tab_bar->WidthAllTabs > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll);
|
||||
if (scrolling_buttons)
|
||||
if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x!
|
||||
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
|
||||
for (int tab_n = 0; tab_n < section->TabCount; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n];
|
||||
tab->Offset = tab_offset;
|
||||
tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f);
|
||||
}
|
||||
tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f);
|
||||
tab_offset += section->Spacing;
|
||||
section_tab_index += section->TabCount;
|
||||
}
|
||||
|
||||
// If we have lost the selected tab, select the next most recently active one
|
||||
if (found_selected_tab_id == false)
|
||||
@ -7104,7 +7209,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
// Update scrolling
|
||||
if (scroll_track_selected_tab_id)
|
||||
if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id))
|
||||
TabBarScrollToTab(tab_bar, scroll_track_selected_tab);
|
||||
TabBarScrollToTab(tab_bar, scroll_track_selected_tab, sections);
|
||||
tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim);
|
||||
tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget);
|
||||
if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)
|
||||
@ -7120,6 +7225,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
tab_bar->ScrollingSpeed = 0.0f;
|
||||
}
|
||||
tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing;
|
||||
tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing;
|
||||
|
||||
// Clear name buffers
|
||||
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
|
||||
@ -7207,16 +7314,22 @@ void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
|
||||
// Called on manual closure attempt
|
||||
void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
{
|
||||
if ((tab_bar->VisibleTabId == tab->ID) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument))
|
||||
IM_ASSERT(!(tab->Flags & ImGuiTabItemFlags_Button));
|
||||
if (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument))
|
||||
{
|
||||
// This will remove a frame of lag for selecting another tab on closure.
|
||||
// However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure
|
||||
tab->WantClose = true;
|
||||
if (tab_bar->VisibleTabId == tab->ID)
|
||||
{
|
||||
tab->LastFrameVisible = -1;
|
||||
tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0;
|
||||
}
|
||||
else if ((tab_bar->VisibleTabId != tab->ID) && (tab->Flags & ImGuiTabItemFlags_UnsavedDocument))
|
||||
}
|
||||
else
|
||||
{
|
||||
// Actually select before expecting closure
|
||||
// Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup)
|
||||
if (tab_bar->VisibleTabId != tab->ID)
|
||||
tab_bar->NextSelectedTabId = tab->ID;
|
||||
}
|
||||
}
|
||||
@ -7227,23 +7340,34 @@ static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling)
|
||||
return ImMax(scrolling, 0.0f);
|
||||
}
|
||||
|
||||
static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImGuiTabBarSection* sections)
|
||||
{
|
||||
if (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing))
|
||||
return;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
|
||||
int order = tab_bar->GetTabOrder(tab);
|
||||
float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f);
|
||||
float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f);
|
||||
|
||||
// Scrolling happens only in the central section (leading/trailing sections are not scrolling)
|
||||
// FIXME: This is all confusing.
|
||||
float scrollable_width = tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing;
|
||||
|
||||
// We make all tabs positions all relative Sections[0].Width to make code simpler
|
||||
float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f);
|
||||
float tab_x2 = tab->Offset - sections[0].Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f);
|
||||
tab_bar->ScrollingTargetDistToVisibility = 0.0f;
|
||||
if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= tab_bar->BarRect.GetWidth()))
|
||||
if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width))
|
||||
{
|
||||
// Scroll to the left
|
||||
tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f);
|
||||
tab_bar->ScrollingTarget = tab_x1;
|
||||
}
|
||||
else if (tab_bar->ScrollingTarget < tab_x2 - tab_bar->BarRect.GetWidth())
|
||||
else if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width)
|
||||
{
|
||||
tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - tab_bar->BarRect.GetWidth()) - tab_bar->ScrollingAnim, 0.0f);
|
||||
tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth();
|
||||
// Scroll to the right
|
||||
tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f);
|
||||
tab_bar->ScrollingTarget = tab_x2 - scrollable_width;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7258,7 +7382,7 @@ void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, in
|
||||
bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId);
|
||||
if (!tab1)
|
||||
if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder))
|
||||
return false;
|
||||
|
||||
//IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools
|
||||
@ -7266,11 +7390,16 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
|
||||
if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)
|
||||
return false;
|
||||
|
||||
// Reordered TabItem must share the same position flags than target
|
||||
ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];
|
||||
if (tab2->Flags & ImGuiTabItemFlags_NoReorder)
|
||||
return false;
|
||||
if ((tab1->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (tab2->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)))
|
||||
return false;
|
||||
|
||||
ImGuiTabItem item_tmp = *tab1;
|
||||
*tab1 = *tab2;
|
||||
*tab2 = item_tmp;
|
||||
tab1 = tab2 = NULL;
|
||||
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)
|
||||
MarkIniSettingsDirty();
|
||||
@ -7288,13 +7417,6 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
|
||||
const ImVec2 backup_cursor_pos = window->DC.CursorPos;
|
||||
//window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255));
|
||||
|
||||
const ImRect avail_bar_rect = tab_bar->BarRect;
|
||||
bool want_clip_rect = !avail_bar_rect.Contains(ImRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(scrolling_buttons_width, 0.0f)));
|
||||
if (want_clip_rect)
|
||||
PushClipRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max + ImVec2(g.Style.ItemInnerSpacing.x, 0.0f), true);
|
||||
|
||||
ImGuiTabItem* tab_to_select = NULL;
|
||||
|
||||
int select_dir = 0;
|
||||
ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text];
|
||||
arrow_col.w *= 0.5f;
|
||||
@ -7305,30 +7427,44 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
|
||||
const float backup_repeat_rate = g.IO.KeyRepeatRate;
|
||||
g.IO.KeyRepeatDelay = 0.250f;
|
||||
g.IO.KeyRepeatRate = 0.200f;
|
||||
window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y);
|
||||
float x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width);
|
||||
window->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y);
|
||||
if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))
|
||||
select_dir = -1;
|
||||
window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width + arrow_button_size.x, tab_bar->BarRect.Min.y);
|
||||
window->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y);
|
||||
if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))
|
||||
select_dir = +1;
|
||||
PopStyleColor(2);
|
||||
g.IO.KeyRepeatRate = backup_repeat_rate;
|
||||
g.IO.KeyRepeatDelay = backup_repeat_delay;
|
||||
|
||||
if (want_clip_rect)
|
||||
PopClipRect();
|
||||
|
||||
ImGuiTabItem* tab_to_scroll_to = NULL;
|
||||
if (select_dir != 0)
|
||||
if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
|
||||
{
|
||||
int selected_order = tab_bar->GetTabOrder(tab_item);
|
||||
int target_order = selected_order + select_dir;
|
||||
tab_to_select = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; // If we are at the end of the list, still scroll to make our tab visible
|
||||
|
||||
// Skip tab item buttons until another tab item is found or end is reached
|
||||
while (tab_to_scroll_to == NULL)
|
||||
{
|
||||
// If we are at the end of the list, still scroll to make our tab visible
|
||||
tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order];
|
||||
|
||||
// Cross through buttons
|
||||
// (even if first/last item is a button, return it so we can update the scroll)
|
||||
if (tab_to_scroll_to->Flags & ImGuiTabItemFlags_Button)
|
||||
{
|
||||
target_order += select_dir;
|
||||
selected_order += select_dir;
|
||||
tab_to_scroll_to = (target_order <= 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
window->DC.CursorPos = backup_cursor_pos;
|
||||
tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f;
|
||||
|
||||
return tab_to_select;
|
||||
return tab_to_scroll_to;
|
||||
}
|
||||
|
||||
static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
|
||||
@ -7355,6 +7491,9 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
if (tab->Flags & ImGuiTabItemFlags_Button)
|
||||
continue;
|
||||
|
||||
const char* tab_name = tab_bar->GetTabName(tab);
|
||||
if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID))
|
||||
tab_to_select = tab;
|
||||
@ -7371,6 +7510,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
|
||||
//-------------------------------------------------------------------------
|
||||
// - BeginTabItem()
|
||||
// - EndTabItem()
|
||||
// - TabItemButton()
|
||||
// - TabItemEx() [Internal]
|
||||
// - SetTabItemClosed()
|
||||
// - TabItemCalcSize() [Internal]
|
||||
@ -7391,6 +7531,8 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
|
||||
IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!");
|
||||
return false;
|
||||
}
|
||||
IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead!
|
||||
|
||||
bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
|
||||
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
|
||||
{
|
||||
@ -7419,6 +7561,22 @@ void ImGui::EndTabItem()
|
||||
window->IDStack.pop_back();
|
||||
}
|
||||
|
||||
bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
ImGuiTabBar* tab_bar = g.CurrentTabBar;
|
||||
if (tab_bar == NULL)
|
||||
{
|
||||
IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!");
|
||||
return false;
|
||||
}
|
||||
return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL);
|
||||
}
|
||||
|
||||
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
|
||||
{
|
||||
// Layout whole tab bar if not already done
|
||||
@ -7444,6 +7602,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
return false;
|
||||
}
|
||||
|
||||
IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button));
|
||||
IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing
|
||||
|
||||
// Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented)
|
||||
if (flags & ImGuiTabItemFlags_NoCloseButton)
|
||||
p_open = NULL;
|
||||
@ -7462,6 +7623,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
tab = &tab_bar->Tabs.back();
|
||||
tab->ID = id;
|
||||
tab->Width = size.x;
|
||||
tab_bar->TabsAddedNew = true;
|
||||
tab_is_new = true;
|
||||
}
|
||||
tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab);
|
||||
@ -7471,6 +7633,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
|
||||
const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;
|
||||
const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount);
|
||||
const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0;
|
||||
tab->LastFrameVisible = g.FrameCount;
|
||||
tab->Flags = flags;
|
||||
tab->Window = docked_window;
|
||||
@ -7488,19 +7651,13 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
tab_bar->TabsNames.append(label, label + strlen(label) + 1); // Append name _with_ the zero-terminator.
|
||||
}
|
||||
|
||||
// If we are not reorderable, always reset offset based on submission order.
|
||||
// (We already handled layout and sizing using the previous known order, but sizing is not affected by order!)
|
||||
if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable))
|
||||
{
|
||||
tab->Offset = tab_bar->OffsetNextTab;
|
||||
tab_bar->OffsetNextTab += tab->Width + g.Style.ItemInnerSpacing.x;
|
||||
}
|
||||
|
||||
// Update selected tab
|
||||
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
|
||||
if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
|
||||
if (!is_tab_button)
|
||||
tab_bar->NextSelectedTabId = id; // New tabs gets activated
|
||||
if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // SetSelected can only be passed on explicit tab bar
|
||||
if (!is_tab_button)
|
||||
tab_bar->NextSelectedTabId = id;
|
||||
|
||||
// Lock visibility
|
||||
@ -7521,6 +7678,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true);
|
||||
ItemAdd(ImRect(), id);
|
||||
PopItemFlag();
|
||||
if (is_tab_button)
|
||||
return false;
|
||||
return tab_contents_visible;
|
||||
}
|
||||
|
||||
@ -7531,15 +7690,19 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
const ImVec2 backup_main_cursor_pos = window->DC.CursorPos;
|
||||
|
||||
// Layout
|
||||
const bool is_central_section = (tab->Flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) == 0;
|
||||
size.x = tab->Width;
|
||||
if (is_central_section)
|
||||
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
|
||||
else
|
||||
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bb(pos, pos + size);
|
||||
|
||||
// We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation)
|
||||
bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x > tab_bar->BarRect.Max.x);
|
||||
const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX);
|
||||
if (want_clip_rect)
|
||||
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true);
|
||||
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true);
|
||||
|
||||
ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos;
|
||||
ItemSize(bb.GetSize(), style.FramePadding.y);
|
||||
@ -7554,12 +7717,12 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
}
|
||||
|
||||
// Click to Select a tab
|
||||
ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap);
|
||||
ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap);
|
||||
if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW))
|
||||
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
|
||||
if (pressed)
|
||||
if (pressed && !is_tab_button)
|
||||
tab_bar->NextSelectedTabId = id;
|
||||
hovered |= (g.HoveredId == id);
|
||||
|
||||
@ -7654,13 +7817,14 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.
|
||||
const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
|
||||
if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)))
|
||||
if (!is_tab_button)
|
||||
tab_bar->NextSelectedTabId = id;
|
||||
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
|
||||
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
|
||||
|
||||
// Render tab label, process close button
|
||||
const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0;
|
||||
const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0;
|
||||
bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible);
|
||||
if (just_closed && p_open != NULL)
|
||||
{
|
||||
@ -7679,6 +7843,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
|
||||
SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
|
||||
IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected
|
||||
if (is_tab_button)
|
||||
return pressed;
|
||||
return tab_contents_visible;
|
||||
}
|
||||
|
||||
@ -7727,7 +7894,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
|
||||
const float width = bb.GetWidth();
|
||||
IM_UNUSED(flags);
|
||||
IM_ASSERT(width > 0.0f);
|
||||
const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f));
|
||||
const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f));
|
||||
const float y1 = bb.Min.y + 1.0f;
|
||||
const float y2 = bb.Max.y + ((flags & ImGuiTabItemFlags_Preview) ? 0.0f : -1.0f);
|
||||
draw_list->PathLineTo(ImVec2(bb.Min.x, y2));
|
||||
@ -8083,7 +8250,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
|
||||
float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n));
|
||||
float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
|
||||
column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
|
||||
column->ClipRect.ClipWith(window->ClipRect);
|
||||
column->ClipRect.ClipWithFull(window->ClipRect);
|
||||
}
|
||||
|
||||
if (columns->Count > 1)
|
||||
|
@ -148,6 +148,8 @@
|
||||
// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right
|
||||
// STB_TEXTEDIT_K_UP keyboard input to move cursor up
|
||||
// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down
|
||||
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
|
||||
// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
|
||||
// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME
|
||||
// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END
|
||||
// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME
|
||||
@ -170,14 +172,10 @@
|
||||
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
||||
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
||||
//
|
||||
// Todo:
|
||||
// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page
|
||||
// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page
|
||||
//
|
||||
// Keyboard input must be encoded as a single integer value; e.g. a character code
|
||||
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
|
||||
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
|
||||
// i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.
|
||||
// i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.
|
||||
//
|
||||
// You can encode other things, such as CONTROL or ALT, in additional bits, and
|
||||
// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example,
|
||||
@ -337,6 +335,10 @@ typedef struct
|
||||
// each textfield keeps its own insert mode state. to keep an app-wide
|
||||
// insert mode, copy this value in/out of the app state
|
||||
|
||||
int row_count_per_page;
|
||||
// page size in number of row.
|
||||
// this value MUST be set to >0 for pageup or pagedown in multilines documents.
|
||||
|
||||
/////////////////////
|
||||
//
|
||||
// private data
|
||||
@ -855,12 +857,16 @@ retry:
|
||||
break;
|
||||
|
||||
case STB_TEXTEDIT_K_DOWN:
|
||||
case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: {
|
||||
case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
|
||||
case STB_TEXTEDIT_K_PGDOWN:
|
||||
case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
|
||||
StbFindState find;
|
||||
StbTexteditRow row;
|
||||
int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
|
||||
int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
|
||||
int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
|
||||
int row_count = is_page ? state->row_count_per_page : 1;
|
||||
|
||||
if (state->single_line) {
|
||||
if (!is_page && state->single_line) {
|
||||
// on windows, up&down in single-line behave like left&right
|
||||
key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
|
||||
goto retry;
|
||||
@ -875,11 +881,19 @@ retry:
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
|
||||
|
||||
// now find character position down a row
|
||||
if (find.length) {
|
||||
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
|
||||
float x;
|
||||
for (j = 0; j < row_count; ++j) {
|
||||
float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
|
||||
int start = find.first_char + find.length;
|
||||
|
||||
if (find.length == 0)
|
||||
break;
|
||||
|
||||
// [DEAR IMGUI]
|
||||
// going down while being on the last line shouldn't bring us to that line end
|
||||
if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
|
||||
break;
|
||||
|
||||
// now find character position down a row
|
||||
state->cursor = start;
|
||||
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
||||
x = row.x0;
|
||||
@ -901,17 +915,25 @@ retry:
|
||||
|
||||
if (sel)
|
||||
state->select_end = state->cursor;
|
||||
|
||||
// go to next line
|
||||
find.first_char = find.first_char + find.length;
|
||||
find.length = row.num_chars;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STB_TEXTEDIT_K_UP:
|
||||
case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: {
|
||||
case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
|
||||
case STB_TEXTEDIT_K_PGUP:
|
||||
case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
|
||||
StbFindState find;
|
||||
StbTexteditRow row;
|
||||
int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
|
||||
int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
|
||||
int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
|
||||
int row_count = is_page ? state->row_count_per_page : 1;
|
||||
|
||||
if (state->single_line) {
|
||||
if (!is_page && state->single_line) {
|
||||
// on windows, up&down become left&right
|
||||
key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
|
||||
goto retry;
|
||||
@ -926,11 +948,14 @@ retry:
|
||||
stb_textedit_clamp(str, state);
|
||||
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
|
||||
|
||||
for (j = 0; j < row_count; ++j) {
|
||||
float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
|
||||
|
||||
// can only go up if there's a previous row
|
||||
if (find.prev_first != find.first_char) {
|
||||
if (find.prev_first == find.first_char)
|
||||
break;
|
||||
|
||||
// now find character position up a row
|
||||
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
|
||||
float x;
|
||||
state->cursor = find.prev_first;
|
||||
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
||||
x = row.x0;
|
||||
@ -952,6 +977,14 @@ retry:
|
||||
|
||||
if (sel)
|
||||
state->select_end = state->cursor;
|
||||
|
||||
// go to previous line
|
||||
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
|
||||
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
|
||||
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
|
||||
--prev_scan;
|
||||
find.first_char = find.prev_first;
|
||||
find.prev_first = prev_scan;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1075,10 +1108,6 @@ retry:
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// @TODO:
|
||||
// STB_TEXTEDIT_K_PGUP - move cursor up a page
|
||||
// STB_TEXTEDIT_K_PGDOWN - move cursor down a page
|
||||
}
|
||||
}
|
||||
|
||||
@ -1134,7 +1163,7 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
state->undo_rec[i].char_storage += n;
|
||||
}
|
||||
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
|
||||
// {DEAR IMGUI]
|
||||
// [DEAR IMGUI]
|
||||
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
||||
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
|
||||
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
|
||||
@ -1350,6 +1379,7 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
|
||||
state->initialized = 1;
|
||||
state->single_line = (unsigned char) is_single_line;
|
||||
state->insert_mode = 0;
|
||||
state->row_count_per_page = 0;
|
||||
}
|
||||
|
||||
// API initialize
|
||||
|
Loading…
Reference in New Issue
Block a user