Merge branch 'master' into docking

# Conflicts:
#	docs/CHANGELOG.txt
#	examples/imgui_impl_opengl3.cpp
#	imgui_widgets.cpp
This commit is contained in:
omar 2019-02-22 12:29:18 +01:00
commit 87ded34f9f
16 changed files with 423 additions and 315 deletions

View File

@ -93,6 +93,24 @@ Other changes:
to make the examples main.cpp easier to read. to make the examples main.cpp easier to read.
-----------------------------------------------------------------------
VERSION 1.69 (In Progress)
-----------------------------------------------------------------------
Other Changes:
- InputInt, InputFloat, InputScalar: Fix to keep the label of the +/- buttons centered when
style.FramePadding.x is abnormally larger than style.FramePadding.y. Since the buttons are
meant to be square (to align with e.g. color button) we always use FramePadding.y. (#2367)
- InputText: Fixed an edge case crash that would happen if another widget sharing the same ID
is being swapped with an InputText that has yet to be activated.
- TabBar: Fixed a crash when using BeginTabBar() recursively (didn't affect docking). (#2371)
- TabBar: Added extra mis-usage error recovery. Past the assert, common mis-usage don't lead to
hard crashes any more, facilitating integration with scripting languages. (#1651)
- Examples: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN
even if the OpenGL headers/loader happens to define the value. (#2366, #2186)
----------------------------------------------------------------------- -----------------------------------------------------------------------
VERSION 1.68 (Released 2019-02-19) VERSION 1.68 (Released 2019-02-19)
----------------------------------------------------------------------- -----------------------------------------------------------------------

View File

@ -102,7 +102,7 @@ Demo Binaries
------------- -------------
You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me 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-20181008.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20181008.zip) (Windows binaries, Dear ImGui 1.66 WIP built 2018/10/08, master branch, 5 executables) - [imgui-demo-binaries-20190219.zip](http://www.dearimgui.org/binaries/imgui-demo-binaries-20190219.zip) (Windows binaries, Dear ImGui 1.68 built 2019/02/19, master branch, 5 executables)
The demo applications are unfortunately not yet 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()`. The demo applications are unfortunately not yet 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()`.

View File

@ -72,8 +72,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725) - input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725)
- input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it. - input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it.
- input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position. - input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position.
- input text: what's the easiest way to implement a nice IP/Mac address input editor? - input text: decorrelate layout from inputs - e.g. what's the easiest way to implement a nice IP/Mac address input editor?
- input text: Global callback system so user can plug in an expression evaluator easily. - input text: global callback system so user can plug in an expression evaluator easily.
- input text: force scroll to end or scroll to a given line/contents (so user can implement a log or a search feature)
- input text: a side bar that could e.g. preview where errors are. probably left to the user to draw but we'd need to give them the info there.
- input text: a way for the user to provide syntax coloring.
- input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc).
- input text multi-line: support for cut/paste without selection (cut/paste the current line) - input text multi-line: support for cut/paste without selection (cut/paste the current line)
- input text multi-line: line numbers? status bar? (follow up on #200) - input text multi-line: line numbers? status bar? (follow up on #200)

View File

@ -85,11 +85,11 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
@ -99,11 +99,11 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
@ -115,14 +115,14 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>
@ -135,14 +135,14 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>

View File

@ -85,11 +85,11 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
@ -99,11 +99,11 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
@ -115,14 +115,14 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>
@ -135,14 +135,14 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;$(SolutionDir)\libs\glfw\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;..\libs\glfw\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(SolutionDir)\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>opengl32.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
@ -85,11 +85,11 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>%VULKAN_SDK%\lib32;$(SolutionDir)\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>%VULKAN_SDK%\lib32;..\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
@ -99,11 +99,11 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>%VULKAN_SDK%\lib;$(SolutionDir)\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>%VULKAN_SDK%\lib;..\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
@ -115,14 +115,14 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>%VULKAN_SDK%\lib32;$(SolutionDir)\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>%VULKAN_SDK%\lib32;..\libs\glfw\lib-vc2010-32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>
@ -135,14 +135,14 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;$(SolutionDir)\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>%VULKAN_SDK%\lib;$(SolutionDir)\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>%VULKAN_SDK%\lib;..\libs\glfw\lib-vc2010-64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>vulkan-1.lib;glfw3.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries> <IgnoreSpecificDefaultLibraries>

View File

@ -85,7 +85,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -99,7 +99,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -115,7 +115,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
@ -135,7 +135,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>

View File

@ -85,7 +85,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -99,7 +99,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -115,7 +115,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>
@ -135,7 +135,7 @@
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;$(SolutionDir)\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..;%SDL2_DIR%\include;..\libs\gl3w;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile> </ClCompile>
<Link> <Link>

View File

@ -85,7 +85,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(DXSDK_DIR)/Lib/x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
@ -98,7 +98,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(DXSDK_DIR)Lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(DXSDK_DIR)/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
@ -116,7 +116,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(DXSDK_DIR)/Lib/x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
@ -134,7 +134,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(DXSDK_DIR)Lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(DXSDK_DIR)/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>

View File

@ -13,10 +13,11 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2018-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. // 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450). // 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT). // 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. // 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES". // 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation. // 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
@ -181,7 +182,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
bool clip_origin_lower_left = true; bool clip_origin_lower_left = true;
#ifdef GL_CLIP_ORIGIN #if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
if (last_clip_origin == GL_UPPER_LEFT) if (last_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false; clip_origin_lower_left = false;

View File

@ -1,4 +1,4 @@
// dear imgui, v1.68 // dear imgui, v1.69 WIP
// (main code and documentation) // (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code. // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
@ -58,9 +58,9 @@ CODE
// [SECTION] FORWARD DECLARATIONS // [SECTION] FORWARD DECLARATIONS
// [SECTION] CONTEXT AND MEMORY ALLOCATORS // [SECTION] CONTEXT AND MEMORY ALLOCATORS
// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) // [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
// [SECTION] MISC HELPER/UTILITIES (Maths, String, Format, Hash, File functions) // [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions)
// [SECTION] MISC HELPER/UTILITIES (ImText* functions) // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
// [SECTION] MISC HELPER/UTILITIES (Color functions) // [SECTION] MISC HELPERS/UTILITIES (Color functions)
// [SECTION] ImGuiStorage // [SECTION] ImGuiStorage
// [SECTION] ImGuiTextFilter // [SECTION] ImGuiTextFilter
// [SECTION] ImGuiTextBuffer // [SECTION] ImGuiTextBuffer
@ -1262,7 +1262,7 @@ void ImGuiIO::ClearInputCharacters()
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] MISC HELPER/UTILITIES (Maths, String, Format, Hash, File functions) // [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
@ -1792,7 +1792,7 @@ int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_e
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] MISC HELPER/UTILTIES (Color functions) // [SECTION] MISC HELPERS/UTILTIES (Color functions)
// Note: The Convert functions are early design which are not consistent with other API. // Note: The Convert functions are early design which are not consistent with other API.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -3807,9 +3807,7 @@ void ImGui::Shutdown(ImGuiContext* context)
IM_DELETE(g.Viewports[i]); IM_DELETE(g.Viewports[i]);
g.Viewports.clear(); g.Viewports.clear();
g.PrivateClipboard.clear(); g.PrivateClipboard.clear();
g.InputTextState.TextW.clear(); g.InputTextState.ClearFreeMemory();
g.InputTextState.InitialText.clear();
g.InputTextState.TempBuffer.clear();
for (int i = 0; i < g.SettingsWindows.Size; i++) for (int i = 0; i < g.SettingsWindows.Size; i++)
IM_DELETE(g.SettingsWindows[i].Name); IM_DELETE(g.SettingsWindows[i].Name);
@ -5753,9 +5751,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Scrollbars // Scrollbars
if (window->ScrollbarX) if (window->ScrollbarX)
Scrollbar(ImGuiLayoutType_Horizontal); Scrollbar(ImGuiAxis_X);
if (window->ScrollbarY) if (window->ScrollbarY)
Scrollbar(ImGuiLayoutType_Vertical); Scrollbar(ImGuiAxis_Y);
// Render resize grips (after their input handling so we don't have a frame of latency) // Render resize grips (after their input handling so we don't have a frame of latency)
if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize))
@ -7131,13 +7129,13 @@ ImGuiID ImGui::GetID(const void* ptr_id)
bool ImGui::IsRectVisible(const ImVec2& size) bool ImGui::IsRectVisible(const ImVec2& size)
{ {
ImGuiWindow* window = GImGui->CurrentWindow;; ImGuiWindow* window = GImGui->CurrentWindow;
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
} }
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
{ {
ImGuiWindow* window = GImGui->CurrentWindow;; ImGuiWindow* window = GImGui->CurrentWindow;
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
} }

View File

@ -1,4 +1,4 @@
// dear imgui, v1.68 // dear imgui, v1.69 WIP
// (headers) // (headers)
// See imgui.cpp file for documentation. // See imgui.cpp file for documentation.
@ -46,8 +46,8 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY00 then bounced up to XYY01 when release tagging happens)
#define IMGUI_VERSION "1.68" #define IMGUI_VERSION "1.69 WIP"
#define IMGUI_VERSION_NUM 16801 #define IMGUI_VERSION_NUM 16899
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert))
#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch #define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch
#define IMGUI_HAS_DOCK 1 // Docking WIP branch #define IMGUI_HAS_DOCK 1 // Docking WIP branch

View File

@ -1,4 +1,4 @@
// dear imgui, v1.68 // dear imgui, v1.69 WIP
// (demo code) // (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: // Message to the person tempted to delete this file when integrating Dear ImGui into their code base:

View File

@ -1,4 +1,4 @@
// dear imgui, v1.68 // dear imgui, v1.69 WIP
// (drawing and font code) // (drawing and font code)
/* /*
@ -83,7 +83,7 @@ Index of this file:
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Compile time options: // Compile time options:
//#define IMGUI_STB_NAMESPACE ImGuiStb //#define IMGUI_STB_NAMESPACE ImStb
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
@ -163,7 +163,7 @@ namespace IMGUI_STB_NAMESPACE
#endif #endif
#ifdef IMGUI_STB_NAMESPACE #ifdef IMGUI_STB_NAMESPACE
} // namespace ImGuiStb } // namespace ImStb
using namespace IMGUI_STB_NAMESPACE; using namespace IMGUI_STB_NAMESPACE;
#endif #endif

View File

@ -1,4 +1,4 @@
// dear imgui, v1.68 // dear imgui, v1.69 WIP
// (internal structures/api) // (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@ -100,7 +100,7 @@ typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags:
// STB libraries includes // STB libraries includes
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
namespace ImGuiStb namespace ImStb
{ {
#undef STB_TEXTEDIT_STRING #undef STB_TEXTEDIT_STRING
@ -110,7 +110,7 @@ namespace ImGuiStb
#define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f #define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f
#include "imstb_textedit.h" #include "imstb_textedit.h"
} // namespace ImGuiStb } // namespace ImStb
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Context pointer // Context pointer
@ -283,6 +283,7 @@ struct IMGUI_API ImPool
T* GetByIndex(ImPoolIdx n) { return &Data[n]; } T* GetByIndex(ImPoolIdx n) { return &Data[n]; }
ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); } ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); }
T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); } T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); }
bool Contains(const T* p) const { return (p >= Data.Data && p < Data.Data + Data.Size); }
void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; } void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; }
T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; } T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; }
void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }
@ -576,16 +577,16 @@ struct IMGUI_API ImGuiMenuColumns
struct IMGUI_API ImGuiInputTextState struct IMGUI_API ImGuiInputTextState
{ {
ImGuiID ID; // widget id owning the text state ImGuiID ID; // widget id owning the text state
int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format.
ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
ImVector<char> InitialText; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) ImVector<char> TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
ImVector<char> TempBuffer; // temporary buffer for callback and other other operations. size=capacity. ImVector<char> InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered)
int CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format.
int BufCapacityA; // end-user buffer capacity int BufCapacityA; // end-user buffer capacity
float ScrollX; float ScrollX; // horizontal scrolling/offset
ImGuiStb::STB_TexteditState StbState; ImStb::STB_TexteditState Stb; // state for stb_textedit.h
float CursorAnim; float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately
bool CursorFollow; bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool SelectedAllMouseLock; bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
// Temporarily set when active // Temporarily set when active
ImGuiInputTextFlags UserFlags; ImGuiInputTextFlags UserFlags;
@ -593,11 +594,12 @@ struct IMGUI_API ImGuiInputTextState
void* UserCallbackData; void* UserCallbackData;
ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } ImGuiInputTextState() { memset(this, 0, sizeof(*this)); }
void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); }
void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); } void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); }
bool HasSelection() const { return StbState.select_start != StbState.select_end; } bool HasSelection() const { return Stb.select_start != Stb.select_end; }
void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; } void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; }
void SelectAll() { StbState.select_start = 0; StbState.cursor = StbState.select_end = CurLenW; StbState.has_preferred_x = 0; } void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; }
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
}; };
@ -815,6 +817,15 @@ struct ImGuiTabBarSortItem
float Width; float Width;
}; };
struct ImGuiTabBarRef
{
ImGuiTabBar* Ptr; // Either field can be set, not both. Dock node tab bars are loose while BeginTabBar() ones are in a pool.
int IndexInMainPool;
ImGuiTabBarRef(ImGuiTabBar* ptr) { Ptr = ptr; IndexInMainPool = -1; }
ImGuiTabBarRef(int index_in_main_pool) { Ptr = NULL; IndexInMainPool = index_in_main_pool; }
};
enum ImGuiDockNodeFlagsPrivate_ enum ImGuiDockNodeFlagsPrivate_
{ {
ImGuiDockNodeFlags_Dockspace = 1 << 10 ImGuiDockNodeFlags_Dockspace = 1 << 10
@ -1017,7 +1028,8 @@ struct ImGuiContext
// Tab bars // Tab bars
ImPool<ImGuiTabBar> TabBars; ImPool<ImGuiTabBar> TabBars;
ImVector<ImGuiTabBar*> CurrentTabBar; ImGuiTabBar* CurrentTabBar;
ImVector<ImGuiTabBarRef> CurrentTabBarStack;
ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer; ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer;
// Widget state // Widget state
@ -1413,7 +1425,7 @@ struct ImGuiItemHoveredDataBackup
enum ImGuiTabBarFlagsPrivate_ enum ImGuiTabBarFlagsPrivate_
{ {
ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around]
ImGuiTabBarFlags_IsFocused = 1 << 21, ImGuiTabBarFlags_IsFocused = 1 << 21,
ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
}; };
@ -1678,8 +1690,8 @@ namespace ImGui
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius);
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags);
IMGUI_API void Scrollbar(ImGuiLayoutType direction); IMGUI_API void Scrollbar(ImGuiAxis axis);
IMGUI_API ImGuiID GetScrollbarID(ImGuiLayoutType direction); IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout.
// Widgets low-level behaviors // Widgets low-level behaviors

View File

@ -1,4 +1,4 @@
// dear imgui, v1.68 // dear imgui, v1.69 WIP
// (widgets code) // (widgets code)
/* /*
@ -741,11 +741,9 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no
return pressed; return pressed;
} }
ImGuiID ImGui::GetScrollbarID(ImGuiLayoutType direction) ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
{ {
ImGuiContext& g = *GImGui; return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY");
ImGuiWindow* window = g.CurrentWindow;
return window->GetID((direction == ImGuiLayoutType_Horizontal) ? "#SCROLLX" : "#SCROLLY");
} }
// Vertical/Horizontal scrollbar // Vertical/Horizontal scrollbar
@ -753,14 +751,15 @@ ImGuiID ImGui::GetScrollbarID(ImGuiLayoutType direction)
// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
void ImGui::Scrollbar(ImGuiLayoutType direction) void ImGui::Scrollbar(ImGuiAxis axis)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
const bool horizontal = (direction == ImGuiLayoutType_Horizontal); const bool horizontal = (axis == ImGuiAxis_X);
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = GetScrollbarID(direction); const ImGuiID id = GetScrollbarID(window, axis);
KeepAliveID(id);
// Render background // Render background
bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
@ -779,7 +778,7 @@ void ImGui::Scrollbar(ImGuiLayoutType direction)
// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab) // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab)
float alpha = 1.0f; float alpha = 1.0f;
if ((direction == ImGuiLayoutType_Vertical) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f) if ((axis == ImGuiAxis_Y) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f)
{ {
alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));
if (alpha <= 0.0f) if (alpha <= 0.0f)
@ -2647,6 +2646,7 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
// FIXME: Facilitate using this in variety of other situations. // FIXME: Facilitate using this in variety of other situations.
bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
{ {
IM_UNUSED(id);
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
// On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id. // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id.
@ -2668,7 +2668,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c
g.ScalarAsInputTextId = g.ActiveId; g.ScalarAsInputTextId = g.ActiveId;
} }
if (value_changed) if (value_changed)
return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.Data, data_type, data_ptr, NULL); return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL);
return false; return false;
} }
@ -2679,7 +2679,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
return false; return false;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; ImGuiStyle& style = g.Style;
IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
if (format == NULL) if (format == NULL)
@ -2701,10 +2701,12 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
PushID(label); PushID(label);
PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format); value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
PopItemWidth(); PopItemWidth();
// Step buttons // Step buttons
const ImVec2 backup_frame_padding = style.FramePadding;
style.FramePadding.x = style.FramePadding.y;
ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups;
if (flags & ImGuiInputTextFlags_ReadOnly) if (flags & ImGuiInputTextFlags_ReadOnly)
button_flags |= ImGuiButtonFlags_Disabled; button_flags |= ImGuiButtonFlags_Disabled;
@ -2722,6 +2724,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
} }
SameLine(0, style.ItemInnerSpacing.x); SameLine(0, style.ItemInnerSpacing.x);
TextUnformatted(label, FindRenderedTextEnd(label)); TextUnformatted(label, FindRenderedTextEnd(label));
style.FramePadding = backup_frame_padding;
PopID(); PopID();
EndGroup(); EndGroup();
@ -2729,7 +2732,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
else else
{ {
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format); value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
} }
return value_changed; return value_changed;
@ -2926,7 +2929,7 @@ static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* t
} }
// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)
namespace ImGuiStb namespace ImStb
{ {
static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
@ -3029,7 +3032,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im
void ImGuiInputTextState::OnKeyPressed(int key) void ImGuiInputTextState::OnKeyPressed(int key)
{ {
stb_textedit_key(this, &StbState, key); stb_textedit_key(this, &Stb, key);
CursorFollow = true; CursorFollow = true;
CursorAnimReset(); CursorAnimReset();
} }
@ -3073,10 +3076,10 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiInputTextState* edit_state = &g.InputTextState; ImGuiInputTextState* edit_state = &g.InputTextState;
IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID);
IM_ASSERT(Buf == edit_state->TempBuffer.Data); IM_ASSERT(Buf == edit_state->TextA.Data);
int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1;
edit_state->TempBuffer.reserve(new_buf_size + 1); edit_state->TextA.reserve(new_buf_size + 1);
Buf = edit_state->TempBuffer.Data; Buf = edit_state->TextA.Data;
BufSize = edit_state->BufCapacityA = new_buf_size; BufSize = edit_state->BufCapacityA = new_buf_size;
} }
@ -3156,7 +3159,8 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. // Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator.
// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. // - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect.
// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h // - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h
// (FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188) // (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are
// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188)
bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -3170,8 +3174,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
ImGuiIO& io = g.IO; ImGuiIO& io = g.IO;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const bool RENDER_SELECTION_WHEN_INACTIVE = true;
const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0;
const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0;
@ -3233,58 +3238,68 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
// NB: we are only allowed to access 'edit_state' if we are the active widget. // NB: we are only allowed to access 'edit_state' if we are the active widget.
ImGuiInputTextState& edit_state = g.InputTextState; ImGuiInputTextState* state = NULL;
if (g.InputTextState.ID == id)
state = &g.InputTextState;
const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing
const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent); const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_clicked = hovered && io.MouseClicked[0];
const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.ID == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY");
const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetScrollbarID(draw_window, ImGuiAxis_Y);
const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y);
bool clear_active_id = false; bool clear_active_id = false;
bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
if (focus_requested || user_clicked || user_scrolled || user_nav_input_start)
const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start);
if (init_make_active && g.ActiveId != id)
{ {
if (g.ActiveId != id) // Access state even if we don't own it yet.
{ state = &g.InputTextState;
// Start edition state->CursorAnimReset();
// Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
// From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
const int prev_len_w = edit_state.CurLenW; const int buf_len = (int)strlen(buf);
const int init_buf_len = (int)strlen(buf); state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string.
edit_state.TextW.resize(buf_size+1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash. memcpy(state->InitialTextA.Data, buf, buf_len + 1);
edit_state.InitialText.resize(init_buf_len + 1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
memcpy(edit_state.InitialText.Data, buf, init_buf_len + 1); // Start edition
const int prev_len_w = state->CurLenW;
const char* buf_end = NULL; const char* buf_end = NULL;
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, buf_size, buf, NULL, &buf_end); state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string.
edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
edit_state.CursorAnimReset(); state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
// Preserve cursor position and undo/redo stack if we come back to same widget // Preserve cursor position and undo/redo stack if we come back to same widget
// FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar). // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
const bool recycle_state = (edit_state.ID == id) && (prev_len_w == edit_state.CurLenW); const bool recycle_state = (state->ID == id) && (prev_len_w == state->CurLenW);
if (recycle_state) if (recycle_state)
{ {
// Recycle existing cursor/selection/undo stack but clamp position // Recycle existing cursor/selection/undo stack but clamp position
// Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
edit_state.CursorClamp(); state->CursorClamp();
} }
else else
{ {
edit_state.ID = id; state->ID = id;
edit_state.ScrollX = 0.0f; state->ScrollX = 0.0f;
stb_textedit_initialize_state(&edit_state.StbState, !is_multiline); stb_textedit_initialize_state(&state->Stb, !is_multiline);
if (!is_multiline && focus_requested_by_code) if (!is_multiline && focus_requested_by_code)
select_all = true; select_all = true;
} }
if (flags & ImGuiInputTextFlags_AlwaysInsertMode) if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
edit_state.StbState.insert_mode = 1; state->Stb.insert_mode = 1;
if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
select_all = true; select_all = true;
} }
if (init_make_active)
{
IM_ASSERT(state && state->ID == id);
SetActiveID(id, window); SetActiveID(id, window);
SetFocusID(id, window); SetFocusID(id, window);
FocusWindow(window); FocusWindow(window);
@ -3292,33 +3307,38 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory)) if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down)); g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
} }
else if (io.MouseClicked[0])
{
// Release focus when we click outside // Release focus when we click outside
if (!init_make_active && io.MouseClicked[0])
clear_active_id = true; clear_active_id = true;
}
// We have an edge case if ActiveId was set through another widget (e.g. widget being swapped)
if (g.ActiveId == id && state == NULL)
ClearActiveID();
bool value_changed = false; bool value_changed = false;
bool enter_pressed = false; bool enter_pressed = false;
int backup_current_text_length = 0; int backup_current_text_length = 0;
// Process mouse inputs and character inputs
if (g.ActiveId == id) if (g.ActiveId == id)
{ {
if (!is_editable && !g.ActiveIdIsJustActivated) IM_ASSERT(state != NULL);
if (is_readonly && !g.ActiveIdIsJustActivated)
{ {
// When read-only we always use the live data passed to the function // When read-only we always use the live data passed to the function
edit_state.TextW.resize(buf_size+1);
const char* buf_end = NULL; const char* buf_end = NULL;
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, edit_state.TextW.Size, buf, NULL, &buf_end); state->TextW.resize(buf_size+1);
edit_state.CurLenA = (int)(buf_end - buf); state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end);
edit_state.CursorClamp(); state->CurLenA = (int)(buf_end - buf);
state->CursorClamp();
} }
backup_current_text_length = edit_state.CurLenA; backup_current_text_length = state->CurLenA;
edit_state.BufCapacityA = buf_size; state->BufCapacityA = buf_size;
edit_state.UserFlags = flags; state->UserFlags = flags;
edit_state.UserCallback = callback; state->UserCallback = callback;
edit_state.UserCallbackData = callback_user_data; state->UserCallbackData = callback_user_data;
// Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
// Down the line we should have a cleaner library-wide concept of Selected vs Active. // Down the line we should have a cleaner library-wide concept of Selected vs Active.
@ -3326,50 +3346,50 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
g.WantTextInputNextFrame = 1; g.WantTextInputNextFrame = 1;
// Edit in progress // Edit in progress
const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
const bool is_osx = io.ConfigMacOSXBehaviors; const bool is_osx = io.ConfigMacOSXBehaviors;
if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0]))
{ {
edit_state.SelectAll(); state->SelectAll();
edit_state.SelectedAllMouseLock = true; state->SelectedAllMouseLock = true;
} }
else if (hovered && is_osx && io.MouseDoubleClicked[0]) else if (hovered && is_osx && io.MouseDoubleClicked[0])
{ {
// Double-click select a word only, OS X style (by simulating keystrokes) // Double-click select a word only, OS X style (by simulating keystrokes)
edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
} }
else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock) else if (io.MouseClicked[0] && !state->SelectedAllMouseLock)
{ {
if (hovered) if (hovered)
{ {
stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y); stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
edit_state.CursorAnimReset(); state->CursorAnimReset();
} }
} }
else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
{ {
stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y); stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);
edit_state.CursorAnimReset(); state->CursorAnimReset();
edit_state.CursorFollow = true; state->CursorFollow = true;
} }
if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) if (state->SelectedAllMouseLock && !io.MouseDown[0])
edit_state.SelectedAllMouseLock = false; state->SelectedAllMouseLock = false;
if (io.InputQueueCharacters.Size > 0) if (io.InputQueueCharacters.Size > 0)
{ {
// Process text input (before we check for Return because using some IME will effectively send a Return?) // Process text input (before we check for Return because using some IME will effectively send a Return?)
// We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters.
bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
if (!ignore_inputs && is_editable && !user_nav_input_start) if (!ignore_inputs && !is_readonly && !user_nav_input_start)
for (int n = 0; n < io.InputQueueCharacters.Size; n++) for (int n = 0; n < io.InputQueueCharacters.Size; n++)
{ {
// Insert character if they pass filtering // Insert character if they pass filtering
unsigned int c = (unsigned int)io.InputQueueCharacters[n]; unsigned int c = (unsigned int)io.InputQueueCharacters[n];
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
edit_state.OnKeyPressed((int)c); state->OnKeyPressed((int)c);
} }
// Consume characters // Consume characters
@ -3377,10 +3397,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
} }
// Process other shortcuts/key-presses
bool cancel_edit = false; bool cancel_edit = false;
if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
{ {
// Handle key-presses IM_ASSERT(state != NULL);
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
const bool is_osx = io.ConfigMacOSXBehaviors; const bool is_osx = io.ConfigMacOSXBehaviors;
const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
@ -3390,27 +3411,29 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper; const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper;
const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper; const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper;
const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection()); const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection()); const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection());
const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable; const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly;
const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && is_editable && is_undoable); const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable);
const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && is_editable && is_undoable; const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable;
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_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_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) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(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) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(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_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } 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)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | 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_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly)
{ {
if (!edit_state.HasSelection()) if (!state->HasSelection())
{ {
if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); if (is_wordmove_key_down)
else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl)
state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
} }
edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
} }
else if (IsKeyPressedMap(ImGuiKey_Enter)) else if (IsKeyPressedMap(ImGuiKey_Enter))
{ {
@ -3419,18 +3442,18 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
{ {
enter_pressed = clear_active_id = true; enter_pressed = clear_active_id = true;
} }
else if (is_editable) else if (!is_readonly)
{ {
unsigned int c = '\n'; // Insert new line unsigned int c = '\n'; // Insert new line
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
edit_state.OnKeyPressed((int)c); state->OnKeyPressed((int)c);
} }
} }
else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable) else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !is_readonly)
{ {
unsigned int c = '\t'; // Insert TAB unsigned int c = '\t'; // Insert TAB
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) if (InputTextFilterCharacter(&c, flags, callback, callback_user_data))
edit_state.OnKeyPressed((int)c); state->OnKeyPressed((int)c);
} }
else if (IsKeyPressedMap(ImGuiKey_Escape)) else if (IsKeyPressedMap(ImGuiKey_Escape))
{ {
@ -3438,31 +3461,33 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
else if (is_undo || is_redo) else if (is_undo || is_redo)
{ {
edit_state.OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
edit_state.ClearSelection(); state->ClearSelection();
} }
else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A))
{ {
edit_state.SelectAll(); state->SelectAll();
edit_state.CursorFollow = true; state->CursorFollow = true;
} }
else if (is_cut || is_copy) else if (is_cut || is_copy)
{ {
// Cut, Copy // Cut, Copy
if (io.SetClipboardTextFn) if (io.SetClipboardTextFn)
{ {
const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0; const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW; const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
edit_state.TempBuffer.resize((ie-ib) * 4 + 1); const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1;
ImTextStrToUtf8(edit_state.TempBuffer.Data, edit_state.TempBuffer.Size, edit_state.TextW.Data+ib, edit_state.TextW.Data+ie); char* clipboard_data = (char*)MemAlloc(clipboard_data_len * sizeof(char));
SetClipboardText(edit_state.TempBuffer.Data); ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
SetClipboardText(clipboard_data);
MemFree(clipboard_data);
} }
if (is_cut) if (is_cut)
{ {
if (!edit_state.HasSelection()) if (!state->HasSelection())
edit_state.SelectAll(); state->SelectAll();
edit_state.CursorFollow = true; state->CursorFollow = true;
stb_textedit_cut(&edit_state, &edit_state.StbState); stb_textedit_cut(state, &state->Stb);
} }
} }
else if (is_paste) else if (is_paste)
@ -3486,25 +3511,27 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
clipboard_filtered[clipboard_filtered_len] = 0; clipboard_filtered[clipboard_filtered_len] = 0;
if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
{ {
stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len); stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len);
edit_state.CursorFollow = true; state->CursorFollow = true;
} }
MemFree(clipboard_filtered); MemFree(clipboard_filtered);
} }
} }
} }
// Process callbacks and apply result back to user's buffer.
if (g.ActiveId == id) if (g.ActiveId == id)
{ {
IM_ASSERT(state != NULL);
const char* apply_new_text = NULL; const char* apply_new_text = NULL;
int apply_new_text_length = 0; int apply_new_text_length = 0;
if (cancel_edit) if (cancel_edit)
{ {
// Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
if (is_editable && strcmp(buf, edit_state.InitialText.Data) != 0) if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0)
{ {
apply_new_text = edit_state.InitialText.Data; apply_new_text = state->InitialTextA.Data;
apply_new_text_length = edit_state.InitialText.Size - 1; apply_new_text_length = state->InitialTextA.Size - 1;
} }
} }
@ -3517,10 +3544,10 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
// FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.
// FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
if (is_editable) if (!is_readonly)
{ {
edit_state.TempBuffer.resize(edit_state.TextW.Size * 4 + 1); state->TextA.resize(state->TextW.Size * 4 + 1);
ImTextStrToUtf8(edit_state.TempBuffer.Data, edit_state.TempBuffer.Size, edit_state.TextW.Data, NULL); ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL);
} }
// User callback // User callback
@ -3558,44 +3585,44 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
callback_data.UserData = callback_user_data; callback_data.UserData = callback_user_data;
callback_data.EventKey = event_key; callback_data.EventKey = event_key;
callback_data.Buf = edit_state.TempBuffer.Data; callback_data.Buf = state->TextA.Data;
callback_data.BufTextLen = edit_state.CurLenA; callback_data.BufTextLen = state->CurLenA;
callback_data.BufSize = edit_state.BufCapacityA; callback_data.BufSize = state->BufCapacityA;
callback_data.BufDirty = false; callback_data.BufDirty = false;
// We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
ImWchar* text = edit_state.TextW.Data; ImWchar* text = state->TextW.Data;
const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor); const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor);
const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start); const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start);
const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end); const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end);
// Call user code // Call user code
callback(&callback_data); callback(&callback_data);
// Read back what user may have modified // Read back what user may have modified
IM_ASSERT(callback_data.Buf == edit_state.TempBuffer.Data); // Invalid to modify those fields IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields
IM_ASSERT(callback_data.BufSize == edit_state.BufCapacityA); IM_ASSERT(callback_data.BufSize == state->BufCapacityA);
IM_ASSERT(callback_data.Flags == flags); IM_ASSERT(callback_data.Flags == flags);
if (callback_data.CursorPos != utf8_cursor_pos) { edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); edit_state.CursorFollow = true; } if (callback_data.CursorPos != utf8_cursor_pos) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; }
if (callback_data.SelectionStart != utf8_selection_start) { edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } if (callback_data.SelectionStart != utf8_selection_start) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }
if (callback_data.SelectionEnd != utf8_selection_end) { edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } if (callback_data.SelectionEnd != utf8_selection_end) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }
if (callback_data.BufDirty) if (callback_data.BufDirty)
{ {
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
if (callback_data.BufTextLen > backup_current_text_length && is_resizable) if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
edit_state.TextW.resize(edit_state.TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length));
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.TextW.Data, edit_state.TextW.Size, callback_data.Buf, NULL); state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);
edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
edit_state.CursorAnimReset(); state->CursorAnimReset();
} }
} }
} }
// Will copy result string if modified // Will copy result string if modified
if (is_editable && strcmp(edit_state.TempBuffer.Data, buf) != 0) if (!is_readonly && strcmp(state->TextA.Data, buf) != 0)
{ {
apply_new_text = edit_state.TempBuffer.Data; apply_new_text = state->TextA.Data;
apply_new_text_length = edit_state.CurLenA; apply_new_text_length = state->CurLenA;
} }
} }
@ -3625,24 +3652,16 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
// Clear temporary user storage // Clear temporary user storage
edit_state.UserFlags = 0; state->UserFlags = 0;
edit_state.UserCallback = NULL; state->UserCallback = NULL;
edit_state.UserCallbackData = NULL; state->UserCallbackData = NULL;
} }
// Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
if (clear_active_id && g.ActiveId == id) if (clear_active_id && g.ActiveId == id)
ClearActiveID(); ClearActiveID();
// Render // Render frame
// Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on.
const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempBuffer.Data : buf; buf = NULL;
// Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line
// without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether.
// Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash.
const int buf_display_max_length = 2 * 1024 * 1024;
if (!is_multiline) if (!is_multiline)
{ {
RenderNavHighlight(frame_bb, id); RenderNavHighlight(frame_bb, id);
@ -3650,33 +3669,51 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
ImVec2 text_size(0.f, 0.f); ImVec2 text_size(0.0f, 0.0f);
const bool is_currently_scrolling = (edit_state.ID == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"));
if (g.ActiveId == id || is_currently_scrolling)
{
edit_state.CursorAnim += io.DeltaTime;
// Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line
// without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether.
// Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash.
const int buf_display_max_length = 2 * 1024 * 1024;
// Select which buffer we are going to display. We set buf to NULL to prevent accidental usage from now on.
const char* buf_display = (state != NULL && !is_readonly) ? state->TextA.Data : buf;
IM_ASSERT(buf_display);
buf = NULL;
// Render text. We currently only render selection when the widget is active or while scrolling.
// FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive.
const bool render_cursor = (g.ActiveId == id) || user_scroll_active;
const bool render_selection = state && state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
if (render_cursor || render_selection)
{
// Render text (with cursor and selection)
// This is going to be messy. We need to: // This is going to be messy. We need to:
// - Display the text (this alone can be more easily clipped) // - Display the text (this alone can be more easily clipped)
// - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
// - Measure text height (for scrollbar) // - Measure text height (for scrollbar)
// We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
// FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
const ImWchar* text_begin = edit_state.TextW.Data; IM_ASSERT(state != NULL);
const ImWchar* text_begin = state->TextW.Data;
ImVec2 cursor_offset, select_start_offset; ImVec2 cursor_offset, select_start_offset;
{ {
// Count lines + find lines numbers straddling 'cursor' and 'select_start' position. // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
const ImWchar* searches_input_ptr[2]; const ImWchar* searches_input_ptr[2] = { NULL, NULL };
searches_input_ptr[0] = text_begin + edit_state.StbState.cursor; int searches_result_line_no[2] = { -1000, -1000 };
searches_input_ptr[1] = NULL; int searches_remaining = 0;
int searches_remaining = 1; if (render_cursor)
int searches_result_line_number[2] = { -1, -999 };
if (edit_state.StbState.select_start != edit_state.StbState.select_end)
{ {
searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end); searches_input_ptr[0] = text_begin + state->Stb.cursor;
searches_result_line_number[1] = -1; searches_result_line_no[0] = -1;
searches_remaining++;
}
if (render_selection)
{
searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
searches_result_line_no[1] = -1;
searches_remaining++; searches_remaining++;
} }
@ -3689,20 +3726,22 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (*s == '\n') if (*s == '\n')
{ {
line_count++; line_count++;
if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; } if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; } if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
} }
line_count++; line_count++;
if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count; if (searches_result_line_no[0] == -1)
if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count; searches_result_line_no[0] = line_count;
if (searches_result_line_no[1] == -1)
searches_result_line_no[1] = line_count;
// Calculate 2d position by finding the beginning of the line and measuring distance // Calculate 2d position by finding the beginning of the line and measuring distance
cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
cursor_offset.y = searches_result_line_number[0] * g.FontSize; cursor_offset.y = searches_result_line_no[0] * g.FontSize;
if (searches_result_line_number[1] >= 0) if (searches_result_line_no[1] >= 0)
{ {
select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
select_start_offset.y = searches_result_line_number[1] * g.FontSize; select_start_offset.y = searches_result_line_no[1] * g.FontSize;
} }
// Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
@ -3711,20 +3750,20 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
// Scroll // Scroll
if (edit_state.CursorFollow) if (render_cursor && state->CursorFollow)
{ {
// Horizontal scroll in chunks of quarter width // Horizontal scroll in chunks of quarter width
if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
{ {
const float scroll_increment_x = size.x * 0.25f; const float scroll_increment_x = size.x * 0.25f;
if (cursor_offset.x < edit_state.ScrollX) if (cursor_offset.x < state->ScrollX)
edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x); state->ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
else if (cursor_offset.x - size.x >= edit_state.ScrollX) else if (cursor_offset.x - size.x >= state->ScrollX)
edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x); state->ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
} }
else else
{ {
edit_state.ScrollX = 0.0f; state->ScrollX = 0.0f;
} }
// Vertical scroll // Vertical scroll
@ -3735,24 +3774,25 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
else if (cursor_offset.y - size.y >= scroll_y) else if (cursor_offset.y - size.y >= scroll_y)
scroll_y = cursor_offset.y - size.y; scroll_y = cursor_offset.y - size.y;
draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
draw_window->Scroll.y = scroll_y; draw_window->Scroll.y = scroll_y;
render_pos.y = draw_window->DC.CursorPos.y; draw_pos.y = draw_window->DC.CursorPos.y;
} }
state->CursorFollow = false;
} }
edit_state.CursorFollow = false;
const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
// Draw selection // Draw selection
if (edit_state.StbState.select_start != edit_state.StbState.select_end) const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f);
if (render_selection)
{ {
const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end); const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end); const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end);
ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
float bg_offy_dn = is_multiline ? 0.0f : 2.0f; float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg); ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;
ImVec2 rect_pos = render_pos + select_start_offset - render_scroll;
for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
{ {
if (rect_pos.y > clip_rect.w + g.FontSize) if (rect_pos.y > clip_rect.w + g.FontSize)
@ -3774,39 +3814,44 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (rect.Overlaps(clip_rect)) if (rect.Overlaps(clip_rect))
draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
} }
rect_pos.x = render_pos.x - render_scroll.x; rect_pos.x = draw_pos.x - draw_scroll.x;
rect_pos.y += g.FontSize; rect_pos.y += g.FontSize;
} }
} }
const int buf_display_len = edit_state.CurLenA; // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.
const int buf_display_len = state->CurLenA;
if (is_multiline || buf_display_len < buf_display_max_length) if (is_multiline || buf_display_len < buf_display_max_length)
draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + buf_display_len, 0.0f, is_multiline ? NULL : &clip_rect); draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + buf_display_len, 0.0f, is_multiline ? NULL : &clip_rect);
// Draw blinking cursor // Draw blinking cursor
bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (g.InputTextState.CursorAnim <= 0.0f) || ImFmod(g.InputTextState.CursorAnim, 1.20f) <= 0.80f; if (render_cursor)
ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll; {
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x+1.0f, cursor_screen_pos.y-1.5f); state->CursorAnim += io.DeltaTime;
bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll;
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
if (is_editable) if (!is_readonly)
{ {
g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
g.PlatformImePosViewport = window->Viewport; g.PlatformImePosViewport = window->Viewport;
} }
} }
}
else else
{ {
// Render text only // Render text only (no selection, no cursor)
const char* buf_end = NULL; const char* buf_end = NULL;
if (is_multiline) if (is_multiline)
text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width
else else
buf_end = buf_display + strlen(buf_display); buf_end = buf_display + strlen(buf_display);
if (is_multiline || (buf_end - buf_display) < buf_display_max_length) if (is_multiline || (buf_end - buf_display) < buf_display_max_length)
draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect); draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
} }
if (is_multiline) if (is_multiline)
@ -3821,7 +3866,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// Log as text // Log as text
if (g.LogEnabled && !is_password) if (g.LogEnabled && !is_password)
LogRenderedText(&render_pos, buf_display, NULL); LogRenderedText(&draw_pos, buf_display, NULL);
if (label_size.x > 0) if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
@ -5896,6 +5941,20 @@ static int IMGUI_CDECL TabBarSortItemComparer(const void* lhs, const void* rhs)
return (b->Index - a->Index); return (b->Index - a->Index);
} }
static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref)
{
ImGuiContext& g = *GImGui;
return ref.Ptr ? ref.Ptr : g.TabBars.GetByIndex(ref.IndexInMainPool);
}
static ImGuiTabBarRef GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
{
ImGuiContext& g = *GImGui;
if (g.TabBars.Contains(tab_bar))
return ImGuiTabBarRef(g.TabBars.GetIndex(tab_bar));
return ImGuiTabBarRef(tab_bar);
}
bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -5920,7 +5979,10 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
if ((flags & ImGuiTabBarFlags_DockNode) == 0) if ((flags & ImGuiTabBarFlags_DockNode) == 0)
window->IDStack.push_back(tab_bar->ID); window->IDStack.push_back(tab_bar->ID);
g.CurrentTabBar.push_back(tab_bar); // Add to stack
g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar));
g.CurrentTabBar = tab_bar;
if (tab_bar->CurrFrameVisible == g.FrameCount) if (tab_bar->CurrFrameVisible == g.FrameCount)
{ {
//IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount); //IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount);
@ -5973,8 +6035,12 @@ void ImGui::EndTabBar()
if (window->SkipItems) if (window->SkipItems)
return; return;
IM_ASSERT(!g.CurrentTabBar.empty()); // Mismatched BeginTabBar/EndTabBar ImGuiTabBar* tab_bar = g.CurrentTabBar;
ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); if (tab_bar == NULL)
{
IM_ASSERT(tab_bar != NULL && "Mismatched BeginTabBar()/EndTabBar()!");
return; // FIXME-ERRORHANDLING
}
if (tab_bar->WantLayout) if (tab_bar->WantLayout)
TabBarLayout(tab_bar); TabBarLayout(tab_bar);
@ -5987,7 +6053,9 @@ void ImGui::EndTabBar()
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
PopID(); PopID();
g.CurrentTabBar.pop_back();
g.CurrentTabBarStack.pop_back();
g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back());
} }
// This is called only once a frame before by the first call to ItemTab() // This is called only once a frame before by the first call to ItemTab()
@ -6201,7 +6269,7 @@ void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGu
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL); IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL);
IM_ASSERT(g.CurrentTabBar.empty()); // Can't work while the tab bar is active as our tab doesn't have an X offset yet IM_ASSERT(g.CurrentTabBar == NULL); // Can't work while the tab bar is active as our tab doesn't have an X offset yet
ImGuiTabItem new_tab; ImGuiTabItem new_tab;
new_tab.ID = window->ID; new_tab.ID = window->ID;
@ -6376,8 +6444,12 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
if (g.CurrentWindow->SkipItems) if (g.CurrentWindow->SkipItems)
return false; return false;
IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!"); ImGuiTabBar* tab_bar = g.CurrentTabBar;
ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); if (tab_bar == NULL)
{
IM_ASSERT(tab_bar && "Needs to be called between BeginTabBar() and EndTabBar()!");
return false; // FIXME-ERRORHANDLING
}
bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
{ {
@ -6393,9 +6465,13 @@ void ImGui::EndTabItem()
if (g.CurrentWindow->SkipItems) if (g.CurrentWindow->SkipItems)
return; return;
IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!"); ImGuiTabBar* tab_bar = g.CurrentTabBar;
ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); if (tab_bar == NULL)
IM_ASSERT(tab_bar->LastTabItemIdx >= 0 && "Needs to be called between BeginTabItem() and EndTabItem()"); {
IM_ASSERT(tab_bar != NULL && "Needs to be called between BeginTabBar() and EndTabBar()!");
return;
}
IM_ASSERT(tab_bar->LastTabItemIdx >= 0);
ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) if (!(tab->Flags & ImGuiTabItemFlags_NoPushId))
g.CurrentWindow->IDStack.pop_back(); g.CurrentWindow->IDStack.pop_back();
@ -6650,10 +6726,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
void ImGui::SetTabItemClosed(const char* label) void ImGui::SetTabItemClosed(const char* label)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
bool is_within_manual_tab_bar = (g.CurrentTabBar.Size > 0) && !(g.CurrentTabBar.back()->Flags & ImGuiTabBarFlags_DockNode); bool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode);
if (is_within_manual_tab_bar) if (is_within_manual_tab_bar)
{ {
ImGuiTabBar* tab_bar = g.CurrentTabBar.back(); ImGuiTabBar* tab_bar = g.CurrentTabBar;
IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem() IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem()
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); ImGuiID tab_id = TabBarCalcTabID(tab_bar, label);
TabBarRemoveTab(tab_bar, tab_id); TabBarRemoveTab(tab_bar, tab_id);