mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 21:21:06 +01:00 
			
		
		
		
	Merge branch 'master' into docking
# Conflicts: # backends/imgui_impl_opengl3.cpp # backends/imgui_impl_osx.h # backends/imgui_impl_osx.mm # imgui.cpp
This commit is contained in:
		
							
								
								
									
										41
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -37,14 +37,10 @@ jobs: | ||||
|       - name: Fix Projects | ||||
|         shell: powershell | ||||
|         run: | | ||||
|           # WARNING: This will need updating if toolset/sdk change in project files! | ||||
|           # CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version. | ||||
|           gci -recurse -filter "*.vcxproj" | ForEach-Object { | ||||
|             # Fix SDK and toolset for most samples. | ||||
|             (Get-Content $_.FullName) -Replace "<PlatformToolset>v110</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName | ||||
|             (Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName | ||||
|             # Fix SDK and toolset for samples that require newer SDK/toolset. At the moment it is only dx12. | ||||
|             (Get-Content $_.FullName) -Replace "<PlatformToolset>v140</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName | ||||
|             (Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName | ||||
|             (Get-Content $_.FullName) -Replace "<PlatformToolset>v\d{3}</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName | ||||
|             (Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>[\d\.]+</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName | ||||
|           } | ||||
|  | ||||
|       # Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long. | ||||
| @@ -497,34 +493,3 @@ jobs: | ||||
|       run: | | ||||
|         cd examples/example_android_opengl3/android | ||||
|         gradle assembleDebug | ||||
|  | ||||
|   Discord-CI: | ||||
|     runs-on: ubuntu-18.04 | ||||
|     if: always() | ||||
|     needs: [Windows, Linux, MacOS, iOS, Emscripten, Android] | ||||
|     steps: | ||||
|     - uses: dearimgui/github_discord_notifier@latest | ||||
|       with: | ||||
|         discord-webhook: ${{ secrets.DISCORD_CI_WEBHOOK }} | ||||
|         github-token: ${{ github.token }} | ||||
|         action-task: discord-jobs | ||||
|         discord-filter: "'{{ github.branch }}'.match(/master|docking/g) != null && '{{ run.conclusion }}' != '{{ last_run.conclusion }}'" | ||||
|         discord-username: GitHub Actions | ||||
|         discord-job-new-failure-message: '' | ||||
|         discord-job-fixed-failure-message: '' | ||||
|         discord-job-new-failure-embed: | | ||||
|           { | ||||
|             "title": "`{{ job.name }}` job is failing on `{{ github.branch }}`!", | ||||
|             "description": "Commit [{{ github.context.payload.head_commit.title }}]({{ github.context.payload.head_commit.url }}) pushed to [{{ github.branch }}]({{ github.branch_url }}) broke [{{ job.name }}]({{ job.url }}) build job.\nFailing steps: {{ failing_steps }}", | ||||
|             "url": "{{ job.url }}", | ||||
|             "color": "0xFF0000", | ||||
|             "timestamp": "{{ run.updated_at }}" | ||||
|           } | ||||
|         discord-job-fixed-failure-embed: | | ||||
|           { | ||||
|             "title": "`{{ github.branch }}` branch is no longer failing!", | ||||
|             "description": "Build failures were fixed on [{{ github.branch }}]({{ github.branch_url }}) branch.", | ||||
|             "color": "0x00FF00", | ||||
|             "url": "{{ github.context.payload.head_commit.url }}", | ||||
|             "timestamp": "{{ run.completed_at }}" | ||||
|           } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
| // CHANGELOG | ||||
| // (minor and older changes stripped away, please see git history for details) | ||||
| //  2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | ||||
| //  2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers. | ||||
| //  2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions. | ||||
| //  2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader. | ||||
| //  2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). | ||||
| @@ -176,6 +177,8 @@ struct ImGui_ImplOpenGL3_Data | ||||
|     GLuint          AttribLocationVtxUV; | ||||
|     GLuint          AttribLocationVtxColor; | ||||
|     unsigned int    VboHandle, ElementsHandle; | ||||
|     GLsizeiptr      VertexBufferSize; | ||||
|     GLsizeiptr      IndexBufferSize; | ||||
|     bool            HasClipOrigin; | ||||
|  | ||||
|     ImGui_ImplOpenGL3_Data() { memset(this, 0, sizeof(*this)); } | ||||
| @@ -436,8 +439,20 @@ void    ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) | ||||
|         const ImDrawList* cmd_list = draw_data->CmdLists[n]; | ||||
|  | ||||
|         // Upload vertex/index buffers | ||||
|         glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); | ||||
|         glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); | ||||
|         GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert); | ||||
|         GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx); | ||||
|         if (bd->VertexBufferSize < vtx_buffer_size) | ||||
|         { | ||||
|             bd->VertexBufferSize = vtx_buffer_size; | ||||
|             glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, NULL, GL_STREAM_DRAW); | ||||
|         } | ||||
|         if (bd->IndexBufferSize < idx_buffer_size) | ||||
|         { | ||||
|             bd->IndexBufferSize = idx_buffer_size; | ||||
|             glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, NULL, GL_STREAM_DRAW); | ||||
|         } | ||||
|         glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data); | ||||
|         glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data); | ||||
|  | ||||
|         for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) | ||||
|         { | ||||
|   | ||||
| @@ -249,11 +249,13 @@ typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); | ||||
| typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); | ||||
| typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); | ||||
| typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); | ||||
| typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); | ||||
| #ifdef GL_GLEXT_PROTOTYPES | ||||
| GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); | ||||
| GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); | ||||
| GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); | ||||
| GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); | ||||
| GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); | ||||
| #endif | ||||
| #endif /* GL_VERSION_1_5 */ | ||||
| #ifndef GL_VERSION_2_0 | ||||
| @@ -447,6 +449,7 @@ union GL3WProcs { | ||||
|         PFNGLBLENDEQUATIONSEPARATEPROC   BlendEquationSeparate; | ||||
|         PFNGLBLENDFUNCSEPARATEPROC       BlendFuncSeparate; | ||||
|         PFNGLBUFFERDATAPROC              BufferData; | ||||
|         PFNGLBUFFERSUBDATAPROC           BufferSubData; | ||||
|         PFNGLCLEARPROC                   Clear; | ||||
|         PFNGLCLEARCOLORPROC              ClearColor; | ||||
|         PFNGLCOMPILESHADERPROC           CompileShader; | ||||
| @@ -506,6 +509,7 @@ GL3W_API extern union GL3WProcs imgl3wProcs; | ||||
| #define glBlendEquationSeparate          imgl3wProcs.gl.BlendEquationSeparate | ||||
| #define glBlendFuncSeparate              imgl3wProcs.gl.BlendFuncSeparate | ||||
| #define glBufferData                     imgl3wProcs.gl.BufferData | ||||
| #define glBufferSubData                  imgl3wProcs.gl.BufferSubData | ||||
| #define glClear                          imgl3wProcs.gl.Clear | ||||
| #define glClearColor                     imgl3wProcs.gl.ClearColor | ||||
| #define glCompileShader                  imgl3wProcs.gl.CompileShader | ||||
| @@ -692,6 +696,7 @@ static const char *proc_names[] = { | ||||
|     "glBlendEquationSeparate", | ||||
|     "glBlendFuncSeparate", | ||||
|     "glBufferData", | ||||
|     "glBufferSubData", | ||||
|     "glClear", | ||||
|     "glClearColor", | ||||
|     "glCompileShader", | ||||
|   | ||||
| @@ -5,11 +5,12 @@ | ||||
| // Implemented features: | ||||
| //  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. | ||||
| //  [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). | ||||
| //  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||||
| //  [X] Platform: Keyboard arrays indexed using kVK_* codes, e.g. ImGui::IsKeyPressed(kVK_Space). | ||||
| // Issues: | ||||
| //  [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters].. | ||||
| //  [ ] Platform: Multi-viewport / platform windows. | ||||
|  | ||||
| // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.  | ||||
| // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. | ||||
| // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. | ||||
| // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. | ||||
| // Read online: https://github.com/ocornut/imgui/tree/master/docs | ||||
| @@ -19,7 +20,7 @@ | ||||
| @class NSEvent; | ||||
| @class NSView; | ||||
|  | ||||
| IMGUI_IMPL_API bool     ImGui_ImplOSX_Init(); | ||||
| IMGUI_IMPL_API bool     ImGui_ImplOSX_Init(NSView* _Nonnull view); | ||||
| IMGUI_IMPL_API void     ImGui_ImplOSX_Shutdown(); | ||||
| IMGUI_IMPL_API void     ImGui_ImplOSX_NewFrame(NSView* _Nullable view); | ||||
| IMGUI_IMPL_API bool     ImGui_ImplOSX_HandleEvent(NSEvent* _Nonnull event, NSView* _Nullable view); | ||||
|   | ||||
| @@ -5,8 +5,9 @@ | ||||
| // Implemented features: | ||||
| //  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. | ||||
| //  [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). | ||||
| //  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. | ||||
| //  [X] Platform: Keyboard arrays indexed using kVK_* codes, e.g. ImGui::IsKeyPressed(kVK_Space). | ||||
| // Issues: | ||||
| //  [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters].. | ||||
| //  [ ] Platform: Multi-viewport / platform windows. | ||||
|  | ||||
| // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. | ||||
| @@ -14,13 +15,17 @@ | ||||
| // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. | ||||
| // Read online: https://github.com/ocornut/imgui/tree/master/docs | ||||
|  | ||||
| #include "imgui.h" | ||||
| #include "imgui_impl_osx.h" | ||||
| #import "imgui.h" | ||||
| #import "imgui_impl_osx.h" | ||||
| #import <Cocoa/Cocoa.h> | ||||
| #include <mach/mach_time.h> | ||||
| #import <mach/mach_time.h> | ||||
| #import <Carbon/Carbon.h> | ||||
| #import <GameController/GameController.h> | ||||
|  | ||||
| // CHANGELOG | ||||
| // (minor and older changes stripped away, please see git history for details) | ||||
| //  2021-12-13: *BREAKING CHANGE* Add NSView parameter to ImGui_ImplOSX_Init(). Generally fix keyboard support. Using kVK_* codes for keyboard keys. | ||||
| //  2021-12-13: Add game controller support. | ||||
| //  2021-09-21: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards. | ||||
| //  2021-08-17: Calling io.AddFocusEvent() on NSApplicationDidBecomeActiveNotification/NSApplicationDidResignActiveNotification events. | ||||
| //  2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key. | ||||
| @@ -38,15 +43,17 @@ | ||||
| //  2018-07-07: Initial version. | ||||
|  | ||||
| @class ImFocusObserver; | ||||
| @class KeyEventResponder; | ||||
|  | ||||
| // Data | ||||
| static double         g_HostClockPeriod = 0.0; | ||||
| static double         g_Time = 0.0; | ||||
| static NSCursor*      g_MouseCursors[ImGuiMouseCursor_COUNT] = {}; | ||||
| static bool           g_MouseCursorHidden = false; | ||||
| static bool           g_MouseJustPressed[ImGuiMouseButton_COUNT] = {}; | ||||
| static bool           g_MouseDown[ImGuiMouseButton_COUNT] = {}; | ||||
| static ImFocusObserver* g_FocusObserver = NULL; | ||||
| static double               g_HostClockPeriod = 0.0; | ||||
| static double               g_Time = 0.0; | ||||
| static NSCursor*            g_MouseCursors[ImGuiMouseCursor_COUNT] = {}; | ||||
| static bool                 g_MouseCursorHidden = false; | ||||
| static bool                 g_MouseJustPressed[ImGuiMouseButton_COUNT] = {}; | ||||
| static bool                 g_MouseDown[ImGuiMouseButton_COUNT] = {}; | ||||
| static ImFocusObserver*     g_FocusObserver = nil; | ||||
| static KeyEventResponder*   g_KeyEventResponder = nil; | ||||
|  | ||||
| // Undocumented methods for creating cursors. | ||||
| @interface NSCursor() | ||||
| @@ -75,6 +82,102 @@ static void resetKeys() | ||||
|     io.KeyCtrl = io.KeyShift = io.KeyAlt = io.KeySuper = false; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  KeyEventResponder implements the NSTextInputClient protocol as is required by the macOS text input manager. | ||||
|  | ||||
|  The macOS text input manager is invoked by calling the interpretKeyEvents method from the keyDown method. | ||||
|  Keyboard events are then evaluated by the macOS input manager and valid text input is passed back via the | ||||
|  insertText:replacementRange method. | ||||
|  | ||||
|  This is the same approach employed by other cross-platform libraries such as SDL2: | ||||
|   https://github.com/spurious/SDL-mirror/blob/e17aacbd09e65a4fd1e166621e011e581fb017a8/src/video/cocoa/SDL_cocoakeyboard.m#L53 | ||||
|  and GLFW: | ||||
|   https://github.com/glfw/glfw/blob/b55a517ae0c7b5127dffa79a64f5406021bf9076/src/cocoa_window.m#L722-L723 | ||||
|  */ | ||||
| @interface KeyEventResponder: NSView<NSTextInputClient> | ||||
| @end | ||||
|  | ||||
| @implementation KeyEventResponder | ||||
|  | ||||
| - (void)viewDidMoveToWindow | ||||
| { | ||||
|     // Ensure self is a first responder to receive the input events. | ||||
|     [self.window makeFirstResponder:self]; | ||||
| } | ||||
|  | ||||
| - (void)keyDown:(NSEvent*)event | ||||
| { | ||||
|     // Call to the macOS input manager system. | ||||
|     [self interpretKeyEvents:@[event]]; | ||||
| } | ||||
|  | ||||
| - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|  | ||||
|     NSString* characters; | ||||
|     if ([aString isKindOfClass:[NSAttributedString class]]) | ||||
|         characters = [aString string]; | ||||
|     else | ||||
|         characters = (NSString*)aString; | ||||
|  | ||||
|     io.AddInputCharactersUTF8(characters.UTF8String); | ||||
| } | ||||
|  | ||||
| - (BOOL)acceptsFirstResponder | ||||
| { | ||||
|     return YES; | ||||
| } | ||||
|  | ||||
| - (void)doCommandBySelector:(SEL)myselector | ||||
| { | ||||
| } | ||||
|  | ||||
| - (nullable NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange | ||||
| { | ||||
|     return nil; | ||||
| } | ||||
|  | ||||
| - (NSUInteger)characterIndexForPoint:(NSPoint)point | ||||
| { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange | ||||
| { | ||||
|     return NSZeroRect; | ||||
| } | ||||
|  | ||||
| - (BOOL)hasMarkedText | ||||
| { | ||||
|     return NO; | ||||
| } | ||||
|  | ||||
| - (NSRange)markedRange | ||||
| { | ||||
|     return NSMakeRange(NSNotFound, 0); | ||||
| } | ||||
|  | ||||
| - (NSRange)selectedRange | ||||
| { | ||||
|     return NSMakeRange(NSNotFound, 0); | ||||
| } | ||||
|  | ||||
| - (void)setMarkedText:(nonnull id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange | ||||
| { | ||||
| } | ||||
|  | ||||
| - (void)unmarkText | ||||
| { | ||||
| } | ||||
|  | ||||
| - (nonnull NSArray<NSAttributedStringKey>*)validAttributesForMarkedText | ||||
| { | ||||
|     return @[]; | ||||
| } | ||||
|  | ||||
| @end | ||||
|  | ||||
| @interface ImFocusObserver : NSObject | ||||
|  | ||||
| - (void)onApplicationBecomeActive:(NSNotification*)aNotification; | ||||
| @@ -104,7 +207,7 @@ static void resetKeys() | ||||
| @end | ||||
|  | ||||
| // Functions | ||||
| bool ImGui_ImplOSX_Init() | ||||
| bool ImGui_ImplOSX_Init(NSView* view) | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|  | ||||
| @@ -116,29 +219,28 @@ bool ImGui_ImplOSX_Init() | ||||
|     io.BackendPlatformName = "imgui_impl_osx"; | ||||
|  | ||||
|     // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeyDown[] array. | ||||
|     const int offset_for_function_keys = 256 - 0xF700; | ||||
|     io.KeyMap[ImGuiKey_Tab]             = '\t'; | ||||
|     io.KeyMap[ImGuiKey_LeftArrow]       = NSLeftArrowFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_RightArrow]      = NSRightArrowFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_UpArrow]         = NSUpArrowFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_DownArrow]       = NSDownArrowFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_PageUp]          = NSPageUpFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_PageDown]        = NSPageDownFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_Home]            = NSHomeFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_End]             = NSEndFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_Insert]          = NSInsertFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_Delete]          = NSDeleteFunctionKey + offset_for_function_keys; | ||||
|     io.KeyMap[ImGuiKey_Backspace]       = 127; | ||||
|     io.KeyMap[ImGuiKey_Space]           = 32; | ||||
|     io.KeyMap[ImGuiKey_Enter]           = 13; | ||||
|     io.KeyMap[ImGuiKey_Escape]          = 27; | ||||
|     io.KeyMap[ImGuiKey_KeyPadEnter]     = 3; | ||||
|     io.KeyMap[ImGuiKey_A]               = 'A'; | ||||
|     io.KeyMap[ImGuiKey_C]               = 'C'; | ||||
|     io.KeyMap[ImGuiKey_V]               = 'V'; | ||||
|     io.KeyMap[ImGuiKey_X]               = 'X'; | ||||
|     io.KeyMap[ImGuiKey_Y]               = 'Y'; | ||||
|     io.KeyMap[ImGuiKey_Z]               = 'Z'; | ||||
|     io.KeyMap[ImGuiKey_Tab]             = kVK_Tab; | ||||
|     io.KeyMap[ImGuiKey_LeftArrow]       = kVK_LeftArrow; | ||||
|     io.KeyMap[ImGuiKey_RightArrow]      = kVK_RightArrow; | ||||
|     io.KeyMap[ImGuiKey_UpArrow]         = kVK_UpArrow; | ||||
|     io.KeyMap[ImGuiKey_DownArrow]       = kVK_DownArrow; | ||||
|     io.KeyMap[ImGuiKey_PageUp]          = kVK_PageUp; | ||||
|     io.KeyMap[ImGuiKey_PageDown]        = kVK_PageDown; | ||||
|     io.KeyMap[ImGuiKey_Home]            = kVK_Home; | ||||
|     io.KeyMap[ImGuiKey_End]             = kVK_End; | ||||
|     io.KeyMap[ImGuiKey_Insert]          = kVK_F13; | ||||
|     io.KeyMap[ImGuiKey_Delete]          = kVK_ForwardDelete; | ||||
|     io.KeyMap[ImGuiKey_Backspace]       = kVK_Delete; | ||||
|     io.KeyMap[ImGuiKey_Space]           = kVK_Space; | ||||
|     io.KeyMap[ImGuiKey_Enter]           = kVK_Return; | ||||
|     io.KeyMap[ImGuiKey_Escape]          = kVK_Escape; | ||||
|     io.KeyMap[ImGuiKey_KeyPadEnter]     = kVK_ANSI_KeypadEnter; | ||||
|     io.KeyMap[ImGuiKey_A]               = kVK_ANSI_A; | ||||
|     io.KeyMap[ImGuiKey_C]               = kVK_ANSI_C; | ||||
|     io.KeyMap[ImGuiKey_V]               = kVK_ANSI_V; | ||||
|     io.KeyMap[ImGuiKey_X]               = kVK_ANSI_X; | ||||
|     io.KeyMap[ImGuiKey_Y]               = kVK_ANSI_Y; | ||||
|     io.KeyMap[ImGuiKey_Z]               = kVK_ANSI_Z; | ||||
|  | ||||
|     // Load cursors. Some of them are undocumented. | ||||
|     g_MouseCursorHidden = false; | ||||
| @@ -191,6 +293,11 @@ bool ImGui_ImplOSX_Init() | ||||
|                                                  name:NSApplicationDidResignActiveNotification | ||||
|                                                object:nil]; | ||||
|  | ||||
|     // Add the NSTextInputClient to the view hierarchy, | ||||
|     // to receive keyboard events and translate them to input text. | ||||
|     g_KeyEventResponder = [[KeyEventResponder alloc] initWithFrame:NSZeroRect]; | ||||
|     [view addSubview:g_KeyEventResponder]; | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @@ -225,8 +332,12 @@ static void ImGui_ImplOSX_UpdateMouseCursorAndButtons() | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Show OS mouse cursor | ||||
|         [g_MouseCursors[g_MouseCursors[imgui_cursor] ? imgui_cursor : ImGuiMouseCursor_Arrow] set]; | ||||
|         NSCursor* desired = g_MouseCursors[imgui_cursor] ?: g_MouseCursors[ImGuiMouseCursor_Arrow]; | ||||
|         // -[NSCursor set] generates measureable overhead if called unconditionally. | ||||
|         if (desired != NSCursor.currentCursor) | ||||
|         { | ||||
|             [desired set]; | ||||
|         } | ||||
|         if (g_MouseCursorHidden) | ||||
|         { | ||||
|             g_MouseCursorHidden = false; | ||||
| @@ -235,6 +346,50 @@ static void ImGui_ImplOSX_UpdateMouseCursorAndButtons() | ||||
|     } | ||||
| } | ||||
|  | ||||
| void ImGui_ImplOSX_UpdateGamepads() | ||||
| { | ||||
|     ImGuiIO& io = ImGui::GetIO(); | ||||
|     memset(io.NavInputs, 0, sizeof(io.NavInputs)); | ||||
|     if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) | ||||
|         return; | ||||
|  | ||||
|     GCController* controller; | ||||
|     if (@available(macOS 11.0, *)) | ||||
|         controller = GCController.current; | ||||
|     else | ||||
|         controller = GCController.controllers.firstObject; | ||||
|  | ||||
|     if (controller == nil || controller.extendedGamepad == nil) | ||||
|     { | ||||
|         io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     GCExtendedGamepad* gp = controller.extendedGamepad; | ||||
|  | ||||
| #define MAP_BUTTON(NAV_NO, NAME) { io.NavInputs[NAV_NO] = gp.NAME.isPressed ? 1.0 : 0.0; } | ||||
|     MAP_BUTTON(ImGuiNavInput_Activate, buttonA); | ||||
|     MAP_BUTTON(ImGuiNavInput_Cancel, buttonB); | ||||
|     MAP_BUTTON(ImGuiNavInput_Menu, buttonX); | ||||
|     MAP_BUTTON(ImGuiNavInput_Input, buttonY); | ||||
|     MAP_BUTTON(ImGuiNavInput_DpadLeft, dpad.left); | ||||
|     MAP_BUTTON(ImGuiNavInput_DpadRight, dpad.right); | ||||
|     MAP_BUTTON(ImGuiNavInput_DpadUp, dpad.up); | ||||
|     MAP_BUTTON(ImGuiNavInput_DpadDown, dpad.down); | ||||
|     MAP_BUTTON(ImGuiNavInput_FocusPrev, leftShoulder); | ||||
|     MAP_BUTTON(ImGuiNavInput_FocusNext, rightShoulder); | ||||
|     MAP_BUTTON(ImGuiNavInput_TweakSlow, leftTrigger); | ||||
|     MAP_BUTTON(ImGuiNavInput_TweakFast, rightTrigger); | ||||
| #undef MAP_BUTTON | ||||
|  | ||||
|     io.NavInputs[ImGuiNavInput_LStickLeft] = gp.leftThumbstick.left.value; | ||||
|     io.NavInputs[ImGuiNavInput_LStickRight] = gp.leftThumbstick.right.value; | ||||
|     io.NavInputs[ImGuiNavInput_LStickUp] = gp.leftThumbstick.up.value; | ||||
|     io.NavInputs[ImGuiNavInput_LStickDown] = gp.leftThumbstick.down.value; | ||||
|  | ||||
|     io.BackendFlags |= ImGuiBackendFlags_HasGamepad; | ||||
| } | ||||
|  | ||||
| void ImGui_ImplOSX_NewFrame(NSView* view) | ||||
| { | ||||
|     // Setup display size | ||||
| @@ -257,19 +412,25 @@ void ImGui_ImplOSX_NewFrame(NSView* view) | ||||
|     g_Time = current_time; | ||||
|  | ||||
|     ImGui_ImplOSX_UpdateMouseCursorAndButtons(); | ||||
|     ImGui_ImplOSX_UpdateGamepads(); | ||||
| } | ||||
|  | ||||
| static int mapCharacterToKey(int c) | ||||
| NSString* NSStringFromPhase(NSEventPhase phase) | ||||
| { | ||||
|     if (c >= 'a' && c <= 'z') | ||||
|         return c - 'a' + 'A'; | ||||
|     if (c == 25) // SHIFT+TAB -> TAB | ||||
|         return 9; | ||||
|     if (c >= 0 && c < 256) | ||||
|         return c; | ||||
|     if (c >= 0xF700 && c < 0xF700 + 256) | ||||
|         return c - 0xF700 + 256; | ||||
|     return -1; | ||||
|     static NSString* strings[] = | ||||
|     { | ||||
|         @"none", | ||||
|         @"began", | ||||
|         @"stationary", | ||||
|         @"changed", | ||||
|         @"ended", | ||||
|         @"cancelled", | ||||
|         @"mayBegin", | ||||
|     }; | ||||
|  | ||||
|     int pos = phase == NSEventPhaseNone ? 0 : __builtin_ctzl((NSUInteger)phase) + 1; | ||||
|  | ||||
|     return strings[pos]; | ||||
| } | ||||
|  | ||||
| bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) | ||||
| @@ -302,6 +463,21 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) | ||||
|  | ||||
|     if (event.type == NSEventTypeScrollWheel) | ||||
|     { | ||||
|         // Ignore canceled events. | ||||
|         // | ||||
|         // From macOS 12.1, scrolling with two fingers and then decelerating | ||||
|         // by tapping two fingers results in two events appearing: | ||||
|         // | ||||
|         // 1. A scroll wheel NSEvent, with a phase == NSEventPhaseMayBegin, when the user taps | ||||
|         // two fingers to decelerate or stop the scroll events. | ||||
|         // | ||||
|         // 2. A scroll wheel NSEvent, with a phase == NSEventPhaseCancelled, when the user releases the | ||||
|         // two-finger tap. It is this event that sometimes contains large values for scrollingDeltaX and | ||||
|         // scrollingDeltaY. When these are added to the current x and y positions of the scrolling view, | ||||
|         // it appears to jump up or down. It can be observed in Preview, various JetBrains IDEs and here. | ||||
|         if (event.phase == NSEventPhaseCancelled) | ||||
|             return false; | ||||
|  | ||||
|         double wheel_dx = 0.0; | ||||
|         double wheel_dy = 0.0; | ||||
|  | ||||
| @@ -323,6 +499,8 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) | ||||
|             wheel_dy = [event deltaY]; | ||||
|         } | ||||
|  | ||||
|         //NSLog(@"dx=%0.3ff, dy=%0.3f, phase=%@", wheel_dx, wheel_dy, NSStringFromPhase(event.phase)); | ||||
|  | ||||
|         if (fabs(wheel_dx) > 0.0) | ||||
|             io.MouseWheelH += (float)wheel_dx * 0.1f; | ||||
|         if (fabs(wheel_dy) > 0.0) | ||||
| @@ -330,57 +508,37 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) | ||||
|         return io.WantCaptureMouse; | ||||
|     } | ||||
|  | ||||
|     // FIXME: All the key handling is wrong and broken. Refer to GLFW's cocoa_init.mm and cocoa_window.mm. | ||||
|     if (event.type == NSEventTypeKeyDown) | ||||
|     if (event.type == NSEventTypeKeyDown || event.type == NSEventTypeKeyUp) | ||||
|     { | ||||
|         NSString* str = [event characters]; | ||||
|         NSUInteger len = [str length]; | ||||
|         for (NSUInteger i = 0; i < len; i++) | ||||
|         { | ||||
|             int c = [str characterAtIndex:i]; | ||||
|             if (!io.KeySuper && !(c >= 0xF700 && c <= 0xFFFF) && c != 127) | ||||
|                 io.AddInputCharacter((unsigned int)c); | ||||
|  | ||||
|             // We must reset in case we're pressing a sequence of special keys while keeping the command pressed | ||||
|             int key = mapCharacterToKey(c); | ||||
|             if (key != -1 && key < 256 && !io.KeySuper) | ||||
|                 resetKeys(); | ||||
|             if (key != -1) | ||||
|                 io.KeysDown[key] = true; | ||||
|         } | ||||
|         return io.WantCaptureKeyboard; | ||||
|     } | ||||
|  | ||||
|     if (event.type == NSEventTypeKeyUp) | ||||
|     { | ||||
|         NSString* str = [event characters]; | ||||
|         NSUInteger len = [str length]; | ||||
|         for (NSUInteger i = 0; i < len; i++) | ||||
|         { | ||||
|             int c = [str characterAtIndex:i]; | ||||
|             int key = mapCharacterToKey(c); | ||||
|             if (key != -1) | ||||
|                 io.KeysDown[key] = false; | ||||
|         } | ||||
|         unsigned short code = event.keyCode; | ||||
|         IM_ASSERT(code >= 0 && code < IM_ARRAYSIZE(io.KeysDown)); | ||||
|         io.KeysDown[code] = event.type == NSEventTypeKeyDown; | ||||
|         NSEventModifierFlags flags = event.modifierFlags; | ||||
|         io.KeyCtrl  = (flags & NSEventModifierFlagControl) != 0; | ||||
|         io.KeyShift = (flags & NSEventModifierFlagShift) != 0; | ||||
|         io.KeyAlt   = (flags & NSEventModifierFlagOption) != 0; | ||||
|         io.KeySuper = (flags & NSEventModifierFlagCommand) != 0; | ||||
|         return io.WantCaptureKeyboard; | ||||
|     } | ||||
|  | ||||
|     if (event.type == NSEventTypeFlagsChanged) | ||||
|     { | ||||
|         unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; | ||||
|  | ||||
|         bool oldKeyCtrl = io.KeyCtrl; | ||||
|         bool oldKeyShift = io.KeyShift; | ||||
|         bool oldKeyAlt = io.KeyAlt; | ||||
|         bool oldKeySuper = io.KeySuper; | ||||
|         io.KeyCtrl      = flags & NSEventModifierFlagControl; | ||||
|         io.KeyShift     = flags & NSEventModifierFlagShift; | ||||
|         io.KeyAlt       = flags & NSEventModifierFlagOption; | ||||
|         io.KeySuper     = flags & NSEventModifierFlagCommand; | ||||
|  | ||||
|         // We must reset them as we will not receive any keyUp event if they where pressed with a modifier | ||||
|         if ((oldKeyShift && !io.KeyShift) || (oldKeyCtrl && !io.KeyCtrl) || (oldKeyAlt && !io.KeyAlt) || (oldKeySuper && !io.KeySuper)) | ||||
|             resetKeys(); | ||||
|         NSEventModifierFlags flags = event.modifierFlags; | ||||
|         switch (event.keyCode) | ||||
|         { | ||||
|         case kVK_Control: | ||||
|             io.KeyCtrl = (flags & NSEventModifierFlagControl) != 0; | ||||
|             break; | ||||
|         case kVK_Shift: | ||||
|             io.KeyShift = (flags & NSEventModifierFlagShift) != 0; | ||||
|             break; | ||||
|         case kVK_Option: | ||||
|             io.KeyAlt = (flags & NSEventModifierFlagOption) != 0; | ||||
|             break; | ||||
|         case kVK_Command: | ||||
|             io.KeySuper = (flags & NSEventModifierFlagCommand) != 0; | ||||
|             break; | ||||
|         } | ||||
|         return io.WantCaptureKeyboard; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -107,6 +107,9 @@ Breaking Changes: | ||||
|  | ||||
| - Removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. | ||||
|   Please open an issue if you think you really need this function. (#3841) | ||||
| - Backends: OSX: Added NSView* parameter to ImGui_ImplOSX_Init(). (#4759) [@stuartcarnie] | ||||
|   Updated Apple+Metal and Apple+GL example applications accordingly. | ||||
|  | ||||
|  | ||||
| Other Changes: | ||||
|  | ||||
| @@ -134,6 +137,10 @@ Other Changes: | ||||
| - Nav: with ImGuiConfigFlags_NavEnableSetMousePos enabled: Fixed absolute mouse position when using | ||||
|   Home/End leads to scrolling. Fixed not setting mouse position when a failed move request (e.g. when | ||||
|   already at edge) reactivates the navigation highlight. | ||||
| - Menus: fixed closing a menu inside a popup/modal by clicking on the popup/modal. (#3496, #4797) | ||||
| - Menus: fixed closing a menu by clicking on its menu-bar item when inside a popup. (#3496, #4797) [@xndcn] | ||||
| - Menus: fixed menu inside a popup/modal not inhibiting hovering of items in the popup/modal. (#3496, #4797) | ||||
| - Menus: fixed sub-menu items inside a popups from closing the popup. | ||||
| - InputText, Nav: fixed repeated calls to SetKeyboardFocusHere() preventing to use InputText(). (#4682) | ||||
| - Inputtext, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761) | ||||
| - InputText: made double-click select word, triple-line select line. Word delimitation logic differs | ||||
| @@ -156,6 +163,8 @@ Other Changes: | ||||
| - Clipper: fixed invalid state when number of frozen table row is smaller than ItemCount. | ||||
| - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose | ||||
|   tooltip when scrolling. (#143) | ||||
| - Fonts: fixed infinite loop in ImFontGlyphRangesBuilder::AddRanges() when passing UINT16_MAX without | ||||
|   the IMGUI_USE_WCHAR32 compile-time option. (#4802) [@SlavicPotato] | ||||
| - Metrics: Added a node showing windows in submission order and showing the Begin() stack. | ||||
| - Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when the | ||||
|   io.MouseDrawCursor flag is enabled). (#4713) [@nobody-special666] | ||||
| @@ -165,12 +174,18 @@ Other Changes: | ||||
| - Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce | ||||
|   likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling | ||||
|   vkCmdSetScissor() explicitly every frame. (#4644) | ||||
| - Backends: OpenGL3: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports | ||||
|   with some Intel HD drivers, and perhaps improve performances. (#4468, #4504, #2981, #3381) [@parbo] | ||||
| - Backends: OpenGL2, Allegro5, Marmalade: Fixed mishandling of the ImDrawCmd::IdxOffset field. | ||||
|   This is an old bug, but due to the way we created drawlists, it never had any visible side-effect before. | ||||
|   The new code for handling Modal and CTRL+Tab dimming/whitening recently made the bug surface. (#4790) | ||||
| - Backends: DX12: Fixed DRAW_EMPTY_SCISSOR_RECTANGLE warnings. (#4775) | ||||
| - Backends: SDL_Renderer: Added support for large meshes (64k+ vertices) with 16-bit indices, | ||||
|   enabling 'ImGuiBackendFlags_RendererHasVtxOffset' in the backend. (#3926) [@rokups] | ||||
| - Backends: OSX: Generally fix keyboard support. Keyboard arrays indexed using kVK_* codes, e.g. | ||||
|   ImGui::IsKeyPressed(kVK_Space). Don't set mouse cursor shape unconditionally. Handle two fingers scroll | ||||
|   cancel event. (#4759, #4253, #1873) [@stuartcarnie] | ||||
| - Backends: OSX: Add Game Controller support (need linking GameController framework) (#4759) [@stuartcarnie] | ||||
| - Backends: WebGPU: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer() and | ||||
|   wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the | ||||
|   in-flux specs says. (#4766) [@meshula] | ||||
|   | ||||
| @@ -201,10 +201,10 @@ Ongoing Dear ImGui development is currently financially supported by users and p | ||||
| - [Blizzard](https://careers.blizzard.com/en-us/openings/engineering/all/all/all/1) | ||||
|  | ||||
| *Double-chocolate sponsors* | ||||
| - [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui) | ||||
| - [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui), [Supercell](https://supercell.com) | ||||
|  | ||||
| *Chocolate sponsors* | ||||
| - [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Adobe](https://www.adobe.com/products/medium.html), [Aras Pranckevičius](https://aras-p.info), [Arkane Studios](https://www.arkane-studios.com), [Epic](https://www.unrealengine.com/en-US/megagrants), [RAD Game Tools](http://www.radgametools.com/), [Supercell](https://supercell.com) | ||||
| - [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Adobe](https://www.adobe.com/products/medium.html), [Aras Pranckevičius](https://aras-p.info), [Arkane Studios](https://www.arkane-studios.com), [Epic](https://www.unrealengine.com/en-US/megagrants), [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [RAD Game Tools](http://www.radgametools.com/) | ||||
|  | ||||
| *Salty-caramel sponsors* | ||||
| - [Framefield](http://framefield.com), [Grinding Gear Games](https://www.grindinggear.com), [Kylotonn](https://www.kylotonn.com), [Next Level Games](https://www.nextlevelgames.com), [O-Net Communications (USA)](http://en.o-netcom.com) | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| 	objects = { | ||||
|  | ||||
| /* Begin PBXBuildFile section */ | ||||
| 		05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; }; | ||||
| 		07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; | ||||
| 		07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; | ||||
| 		5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; | ||||
| @@ -32,6 +33,7 @@ | ||||
| /* End PBXBuildFile section */ | ||||
|  | ||||
| /* Begin PBXFileReference section */ | ||||
| 		05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; | ||||
| 		07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; }; | ||||
| 		07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; }; | ||||
| 		5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; }; | ||||
| @@ -76,6 +78,7 @@ | ||||
| 			files = ( | ||||
| 				8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */, | ||||
| 				83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */, | ||||
| 				05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */, | ||||
| 				83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */, | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| @@ -133,6 +136,7 @@ | ||||
| 		83BBE9E320EB46B800295997 /* Frameworks */ = { | ||||
| 			isa = PBXGroup; | ||||
| 			children = ( | ||||
| 				05318E0E274C397200A8DE2E /* GameController.framework */, | ||||
| 				8309BDC5253CCCFE0045E2A1 /* AppKit.framework */, | ||||
| 				8309BD8E253CCAAA0045E2A1 /* UIKit.framework */, | ||||
| 				83BBE9EE20EB471C00295997 /* ModelIO.framework */, | ||||
|   | ||||
| @@ -119,7 +119,7 @@ | ||||
|         return event; | ||||
|     }]; | ||||
|  | ||||
|     ImGui_ImplOSX_Init(); | ||||
|     ImGui_ImplOSX_Init(self.view); | ||||
|  | ||||
| #endif | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| 	objects = { | ||||
|  | ||||
| /* Begin PBXBuildFile section */ | ||||
| 		05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05E31B57274EF0360083FCB6 /* GameController.framework */; }; | ||||
| 		07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82EDA213941D00078D120 /* imgui_widgets.cpp */; }; | ||||
| 		4080A99820B02D340036BA46 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A98A20B02CD90036BA46 /* main.mm */; }; | ||||
| 		4080A9A220B034280036BA46 /* imgui_impl_opengl2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99E20B034280036BA46 /* imgui_impl_opengl2.cpp */; }; | ||||
| @@ -32,6 +33,7 @@ | ||||
| /* End PBXCopyFilesBuildPhase section */ | ||||
|  | ||||
| /* Begin PBXFileReference section */ | ||||
| 		05E31B57274EF0360083FCB6 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; | ||||
| 		07A82EDA213941D00078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; }; | ||||
| 		4080A96B20B029B00036BA46 /* example_osx_opengl2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = example_osx_opengl2; sourceTree = BUILT_PRODUCTS_DIR; }; | ||||
| 		4080A98A20B02CD90036BA46 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = SOURCE_ROOT; }; | ||||
| @@ -57,6 +59,7 @@ | ||||
| 			files = ( | ||||
| 				4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */, | ||||
| 				4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */, | ||||
| 				05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */, | ||||
| 			); | ||||
| 			runOnlyForDeploymentPostprocessing = 0; | ||||
| 		}; | ||||
| @@ -95,6 +98,7 @@ | ||||
| 		4080A9B120B034E40036BA46 /* Frameworks */ = { | ||||
| 			isa = PBXGroup; | ||||
| 			children = ( | ||||
| 				05E31B57274EF0360083FCB6 /* GameController.framework */, | ||||
| 				4080A9B420B034EA0036BA46 /* OpenGL.framework */, | ||||
| 				4080A9B220B034E40036BA46 /* Cocoa.framework */, | ||||
| 			); | ||||
|   | ||||
| @@ -59,7 +59,7 @@ | ||||
|     //ImGui::StyleColorsClassic(); | ||||
|  | ||||
|     // Setup Platform/Renderer backends | ||||
|     ImGui_ImplOSX_Init(); | ||||
|     ImGui_ImplOSX_Init(self); | ||||
|     ImGui_ImplOpenGL2_Init(); | ||||
|  | ||||
|     // Load Fonts | ||||
| @@ -147,12 +147,9 @@ | ||||
|         animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES]; | ||||
| } | ||||
|  | ||||
| -(void)reshape                              { [[self openGLContext] update]; [self updateAndDrawDemoView]; } | ||||
| -(void)reshape                              { [super reshape]; [[self openGLContext] update]; [self updateAndDrawDemoView]; } | ||||
| -(void)drawRect:(NSRect)bounds              { [self updateAndDrawDemoView]; } | ||||
| -(void)animationTimerFired:(NSTimer*)timer  { [self setNeedsDisplay:YES]; } | ||||
| -(BOOL)acceptsFirstResponder                { return (YES); } | ||||
| -(BOOL)becomeFirstResponder                 { return (YES); } | ||||
| -(BOOL)resignFirstResponder                 { return (YES); } | ||||
| -(void)dealloc                              { animationTimer = nil; } | ||||
|  | ||||
| //----------------------------------------------------------------------------------- | ||||
|   | ||||
							
								
								
									
										41
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -5544,6 +5544,27 @@ static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settin | ||||
|     window->DockOrder = settings->DockOrder; | ||||
| } | ||||
|  | ||||
| static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const ImGuiWindowFlags old_flags = window->Flags; | ||||
|     const bool child_flag_changed = (new_flags & ImGuiWindowFlags_ChildWindow) != (old_flags & ImGuiWindowFlags_ChildWindow); | ||||
|  | ||||
|     if ((just_created || child_flag_changed) && !(new_flags & ImGuiWindowFlags_ChildWindow)) | ||||
|     { | ||||
|         g.WindowsFocusOrder.push_back(window); | ||||
|         window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); | ||||
|     } | ||||
|     else if (child_flag_changed && (new_flags & ImGuiWindowFlags_ChildWindow)) | ||||
|     { | ||||
|         IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); | ||||
|         for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) | ||||
|             g.WindowsFocusOrder[n]->FocusOrder--; | ||||
|         g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); | ||||
|         window->FocusOrder = -1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -5584,16 +5605,12 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) | ||||
|         window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); | ||||
|     } | ||||
|  | ||||
|     if (!(flags & ImGuiWindowFlags_ChildWindow)) | ||||
|     { | ||||
|         g.WindowsFocusOrder.push_back(window); | ||||
|         window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); | ||||
|     } | ||||
|  | ||||
|     if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) | ||||
|         g.Windows.push_front(window); // Quite slow but rare and only once | ||||
|     else | ||||
|         g.Windows.push_back(window); | ||||
|     UpdateWindowInFocusOrderList(window, true, window->Flags); | ||||
|  | ||||
|     return window; | ||||
| } | ||||
|  | ||||
| @@ -6279,6 +6296,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
|     const bool window_just_created = (window == NULL); | ||||
|     if (window_just_created) | ||||
|         window = CreateNewWindow(name, flags); | ||||
|     else | ||||
|         UpdateWindowInFocusOrderList(window, window_just_created, flags); | ||||
|  | ||||
|     // Automatically disable manual moving/resizing when NoInputs is set | ||||
|     if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) | ||||
| @@ -6372,6 +6391,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
|     window_stack_data.StackSizesOnBegin.SetToCurrentState(); | ||||
|     g.CurrentWindowStack.push_back(window_stack_data); | ||||
|     g.CurrentWindow = NULL; | ||||
|     if (flags & ImGuiWindowFlags_ChildMenu) | ||||
|         g.BeginMenuCount++; | ||||
|  | ||||
|     if (flags & ImGuiWindowFlags_Popup) | ||||
|     { | ||||
| @@ -7107,6 +7128,8 @@ void ImGui::End() | ||||
|  | ||||
|     // Pop from window stack | ||||
|     g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup; | ||||
|     if (window->Flags & ImGuiWindowFlags_ChildMenu) | ||||
|         g.BeginMenuCount--; | ||||
|     if (window->Flags & ImGuiWindowFlags_Popup) | ||||
|         g.BeginPopupStack.pop_back(); | ||||
|     g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithCurrentState(); | ||||
| @@ -9302,7 +9325,7 @@ void ImGui::CloseCurrentPopup() | ||||
|         ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; | ||||
|         bool close_parent = false; | ||||
|         if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|             if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) | ||||
|             if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar)) | ||||
|                 close_parent = true; | ||||
|         if (!close_parent) | ||||
|             break; | ||||
| @@ -9330,7 +9353,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) | ||||
|  | ||||
|     char name[20]; | ||||
|     if (flags & ImGuiWindowFlags_ChildMenu) | ||||
|         ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth | ||||
|         ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth | ||||
|     else | ||||
|         ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame | ||||
|  | ||||
| @@ -17583,7 +17606,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con | ||||
|     } | ||||
|  | ||||
|     ImDrawList* fg_draw_list = viewport ? GetForegroundDrawList(viewport) : NULL; // Render additional visuals into the top-most draw list | ||||
|     if (window && fg_draw_list && IsItemHovered()) | ||||
|     if (window && IsItemHovered() && fg_draw_list) | ||||
|         fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); | ||||
|     if (!node_open) | ||||
|         return; | ||||
|   | ||||
							
								
								
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							| @@ -65,7 +65,7 @@ Index of this file: | ||||
| // Version | ||||
| // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) | ||||
| #define IMGUI_VERSION               "1.86 WIP" | ||||
| #define IMGUI_VERSION_NUM           18518 | ||||
| #define IMGUI_VERSION_NUM           18521 | ||||
| #define IMGUI_CHECKVERSION()        ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) | ||||
| #define IMGUI_HAS_TABLE | ||||
| #define IMGUI_HAS_VIEWPORT          // Viewport WIP branch | ||||
|   | ||||
| @@ -3418,11 +3418,26 @@ static void ShowDemoWindowPopups() | ||||
|         } | ||||
|  | ||||
|         // Call the more complete ShowExampleMenuFile which we use in various places of this demo | ||||
|         if (ImGui::Button("File Menu..")) | ||||
|         if (ImGui::Button("With a menu..")) | ||||
|             ImGui::OpenPopup("my_file_popup"); | ||||
|         if (ImGui::BeginPopup("my_file_popup")) | ||||
|         if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar)) | ||||
|         { | ||||
|             ShowExampleMenuFile(); | ||||
|             if (ImGui::BeginMenuBar()) | ||||
|             { | ||||
|                 if (ImGui::BeginMenu("File")) | ||||
|                 { | ||||
|                     ShowExampleMenuFile(); | ||||
|                     ImGui::EndMenu(); | ||||
|                 } | ||||
|                 if (ImGui::BeginMenu("Edit")) | ||||
|                 { | ||||
|                     ImGui::MenuItem("Dummy"); | ||||
|                     ImGui::EndMenu(); | ||||
|                 } | ||||
|                 ImGui::EndMenuBar(); | ||||
|             } | ||||
|             ImGui::Text("Hello from popup!"); | ||||
|             ImGui::Button("This is a dummy button.."); | ||||
|             ImGui::EndPopup(); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -3088,8 +3088,8 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) | ||||
| void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) | ||||
| { | ||||
|     for (; ranges[0]; ranges += 2) | ||||
|         for (ImWchar c = ranges[0]; c <= ranges[1]; c++) | ||||
|             AddChar(c); | ||||
|         for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 | ||||
|             AddChar((ImWchar)c); | ||||
| } | ||||
|  | ||||
| void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges) | ||||
|   | ||||
| @@ -1758,6 +1758,7 @@ struct ImGuiContext | ||||
|     ImVector<ImGuiGroupData>GroupStack;                         // Stack for BeginGroup()/EndGroup() - not inherited by Begin() | ||||
|     ImVector<ImGuiPopupData>OpenPopupStack;                     // Which popups are open (persistent) | ||||
|     ImVector<ImGuiPopupData>BeginPopupStack;                    // Which level of BeginPopup() we are in (reset every frame) | ||||
|     int                     BeginMenuCount; | ||||
|  | ||||
|     // Viewports | ||||
|     ImVector<ImGuiViewportP*> Viewports;                        // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData. | ||||
| @@ -1993,6 +1994,7 @@ struct ImGuiContext | ||||
|         LastActiveIdTimer = 0.0f; | ||||
|  | ||||
|         CurrentItemFlags = ImGuiItemFlags_None; | ||||
|         BeginMenuCount = 0; | ||||
|  | ||||
|         CurrentDpiScale = 0.0f; | ||||
|         CurrentViewport = NULL; | ||||
|   | ||||
| @@ -3703,11 +3703,11 @@ static int  is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) | ||||
| static int  is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)       { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx])) : 1; } | ||||
| static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx)   { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } | ||||
| static int  STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } | ||||
| static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } | ||||
| #define STB_TEXTEDIT_MOVEWORDLEFT   STB_TEXTEDIT_MOVEWORDLEFT_IMPL    // They need to be #define for stb_textedit.h | ||||
| #ifdef __APPLE__    // FIXME: Move setting to IO structure | ||||
| #define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_MAC | ||||
| #else | ||||
| static int  STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx)   { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } | ||||
| #define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_WIN | ||||
| #endif | ||||
|  | ||||
| @@ -6883,6 +6883,23 @@ void ImGui::EndMainMenuBar() | ||||
|     End(); | ||||
| } | ||||
|  | ||||
| static bool IsRootOfOpenMenuSet() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|         return false; | ||||
|  | ||||
|     // Initially we used 'OpenParentId' to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) based on parent ID. | ||||
|     // This would however prevent the use of e.g. PuhsID() user code submitting menus. | ||||
|     // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag, | ||||
|     // making  hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. | ||||
|     // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup | ||||
|     // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first chilld menu. | ||||
|     const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; | ||||
|     return (/*upper_popup->OpenParentId == window->IDStack.back() &&*/ upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu)); | ||||
| } | ||||
|  | ||||
| bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
| @@ -6895,8 +6912,9 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) | ||||
|     bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); | ||||
|  | ||||
|     // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) | ||||
|     // The first menu in a hierarchy isn't so hovering doesn't get accross (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. | ||||
|     ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; | ||||
|     if (window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) | ||||
|     if (window->Flags & ImGuiWindowFlags_ChildMenu) | ||||
|         flags |= ImGuiWindowFlags_ChildWindow; | ||||
|  | ||||
|     // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). | ||||
| @@ -6915,11 +6933,12 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) | ||||
|     g.MenusIdSubmittedThisFrame.push_back(id); | ||||
|  | ||||
|     ImVec2 label_size = CalcTextSize(label, NULL, true); | ||||
|     bool pressed; | ||||
|     bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back()); | ||||
|  | ||||
|     // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) | ||||
|     const bool menuset_is_open = IsRootOfOpenMenuSet(); | ||||
|     ImGuiWindow* backed_nav_window = g.NavWindow; | ||||
|     if (menuset_is_open) | ||||
|         g.NavWindow = window;  // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) | ||||
|         g.NavWindow = window; | ||||
|  | ||||
|     // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, | ||||
|     // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). | ||||
| @@ -6929,6 +6948,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) | ||||
|     if (!enabled) | ||||
|         BeginDisabled(); | ||||
|     const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | ||||
|     bool pressed; | ||||
|     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | ||||
|     { | ||||
|         // Menu inside an horizontal menu bar | ||||
| @@ -7088,13 +7108,19 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut | ||||
|     ImVec2 pos = window->DC.CursorPos; | ||||
|     ImVec2 label_size = CalcTextSize(label, NULL, true); | ||||
|  | ||||
|     const bool menuset_is_open = IsRootOfOpenMenuSet(); | ||||
|     ImGuiWindow* backed_nav_window = g.NavWindow; | ||||
|     if (menuset_is_open) | ||||
|         g.NavWindow = window; | ||||
|  | ||||
|     // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), | ||||
|     // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. | ||||
|     bool pressed; | ||||
|     PushID(label); | ||||
|     if (!enabled) | ||||
|         BeginDisabled(); | ||||
|     const ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover; | ||||
|  | ||||
|     const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover; | ||||
|     const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | ||||
|     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | ||||
|     { | ||||
| @@ -7104,7 +7130,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut | ||||
|         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); | ||||
|         ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); | ||||
|         PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); | ||||
|         pressed = Selectable("", selected, flags, ImVec2(w, 0.0f)); | ||||
|         pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); | ||||
|         PopStyleVar(); | ||||
|         RenderText(text_pos, label); | ||||
|         window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). | ||||
| @@ -7119,7 +7145,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut | ||||
|         float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); | ||||
|         float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame | ||||
|         float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); | ||||
|         pressed = Selectable("", false, flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); | ||||
|         pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); | ||||
|         RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); | ||||
|         if (icon_w > 0.0f) | ||||
|             RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); | ||||
| @@ -7136,6 +7162,8 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut | ||||
|     if (!enabled) | ||||
|         EndDisabled(); | ||||
|     PopID(); | ||||
|     if (menuset_is_open) | ||||
|         g.NavWindow = backed_nav_window; | ||||
|  | ||||
|     return pressed; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user