mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 13:11:05 +01:00 
			
		
		
		
	Merge branch 'master' into docking
# Conflicts: # imgui.cpp
This commit is contained in:
		| @@ -179,7 +179,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) | ||||
|  | ||||
|                 // Apply scissor/clipping rectangle, Draw | ||||
|                 ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID(); | ||||
|                 al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x, clip_max.y); | ||||
|                 al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y); | ||||
|                 al_draw_prim(&vertices[0], bd->VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); | ||||
|             } | ||||
|             idx_offset += pcmd->ElemCount; | ||||
|   | ||||
| @@ -1,3 +1,22 @@ | ||||
| //----------------------------------------------------------------------------- | ||||
| // About imgui_impl_opengl3_loader.h: | ||||
| // | ||||
| // We embed our own OpenGL loader to not require user to provide their own or to have to use ours, | ||||
| // which proved to be endless problems for users. | ||||
| // Our loader is custom-generated, based on gl3w but automatically filtered to only include | ||||
| // enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small. | ||||
| // | ||||
| // YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY. | ||||
| // THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE. | ||||
| // | ||||
| // Regenerate with: | ||||
| //   python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt | ||||
| // | ||||
| // More info: | ||||
| //   https://github.com/dearimgui/gl3w_stripped | ||||
| //   https://github.com/ocornut/imgui/issues/4445 | ||||
| //----------------------------------------------------------------------------- | ||||
|  | ||||
| /* | ||||
|  * This file was generated with gl3w_gen.py, part of imgl3w | ||||
|  * (hosted at https://github.com/dearimgui/gl3w_stripped) | ||||
| @@ -26,14 +45,11 @@ | ||||
|  * OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| // We embed our own OpenGL loader to not require user to provide their own or to have to use ours, which proved to be endless problems for users. | ||||
| // Our loader is custom-generated, based on gl3w but automatically filtered to only include enums/functions that we use in this source file. | ||||
| // Regenerate with: python gl3w_gen.py --imgui-dir /path/to/imgui/ | ||||
| // see https://github.com/dearimgui/gl3w_stripped for more info. | ||||
| #ifndef __gl3w_h_ | ||||
| #define __gl3w_h_ | ||||
|  | ||||
| // Adapted from KHR/khrplatform.h to avoid including entire file. | ||||
| #ifndef __khrplatform_h_ | ||||
| typedef          float         khronos_float_t; | ||||
| typedef signed   char          khronos_int8_t; | ||||
| typedef unsigned char          khronos_uint8_t; | ||||
| @@ -58,6 +74,7 @@ typedef          uint64_t      khronos_uint64_t; | ||||
| typedef signed   long long     khronos_int64_t; | ||||
| typedef unsigned long long     khronos_uint64_t; | ||||
| #endif | ||||
| #endif  // __khrplatform_h_ | ||||
|  | ||||
| #ifndef __gl_glcorearb_h_ | ||||
| #define __gl_glcorearb_h_ 1 | ||||
| @@ -162,6 +179,7 @@ typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap); | ||||
| typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap); | ||||
| typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); | ||||
| typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); | ||||
| typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void); | ||||
| typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data); | ||||
| typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); | ||||
| typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap); | ||||
| @@ -177,6 +195,7 @@ GLAPI void APIENTRY glDisable (GLenum cap); | ||||
| GLAPI void APIENTRY glEnable (GLenum cap); | ||||
| GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param); | ||||
| GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); | ||||
| GLAPI GLenum APIENTRY glGetError (void); | ||||
| GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data); | ||||
| GLAPI const GLubyte *APIENTRY glGetString (GLenum name); | ||||
| GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap); | ||||
| @@ -416,7 +435,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc); | ||||
|  | ||||
| /* gl3w internal state */ | ||||
| union GL3WProcs { | ||||
|     GL3WglProc ptr[52]; | ||||
|     GL3WglProc ptr[53]; | ||||
|     struct { | ||||
|         PFNGLACTIVETEXTUREPROC           ActiveTexture; | ||||
|         PFNGLATTACHSHADERPROC            AttachShader; | ||||
| @@ -448,6 +467,7 @@ union GL3WProcs { | ||||
|         PFNGLGENTEXTURESPROC             GenTextures; | ||||
|         PFNGLGENVERTEXARRAYSPROC         GenVertexArrays; | ||||
|         PFNGLGETATTRIBLOCATIONPROC       GetAttribLocation; | ||||
|         PFNGLGETERRORPROC                GetError; | ||||
|         PFNGLGETINTEGERVPROC             GetIntegerv; | ||||
|         PFNGLGETPROGRAMINFOLOGPROC       GetProgramInfoLog; | ||||
|         PFNGLGETPROGRAMIVPROC            GetProgramiv; | ||||
| @@ -506,6 +526,7 @@ GL3W_API extern union GL3WProcs imgl3wProcs; | ||||
| #define glGenTextures                    imgl3wProcs.gl.GenTextures | ||||
| #define glGenVertexArrays                imgl3wProcs.gl.GenVertexArrays | ||||
| #define glGetAttribLocation              imgl3wProcs.gl.GetAttribLocation | ||||
| #define glGetError                       imgl3wProcs.gl.GetError | ||||
| #define glGetIntegerv                    imgl3wProcs.gl.GetIntegerv | ||||
| #define glGetProgramInfoLog              imgl3wProcs.gl.GetProgramInfoLog | ||||
| #define glGetProgramiv                   imgl3wProcs.gl.GetProgramiv | ||||
| @@ -691,6 +712,7 @@ static const char *proc_names[] = { | ||||
|     "glGenTextures", | ||||
|     "glGenVertexArrays", | ||||
|     "glGetAttribLocation", | ||||
|     "glGetError", | ||||
|     "glGetIntegerv", | ||||
|     "glGetProgramInfoLog", | ||||
|     "glGetProgramiv", | ||||
|   | ||||
| @@ -42,18 +42,25 @@ Breaking Changes: | ||||
|  | ||||
| Other Changes: | ||||
|  | ||||
| - Windows: fixed background order of overlapping childs submitted sequentially. (#4493) | ||||
| - Windows: Fixed background order of overlapping childs submitted sequentially. (#4493) | ||||
| - InputTextMultiline: Fixed label size not being included into window contents rect unless | ||||
|   the whole widget is clipped. | ||||
| - InputText: Allow cancelling/validating input with gamepad nav events to facilitate undoing | ||||
|   an accidental press on NavInput (Triangle button on PS4/PS5) without a wired keyboard. (#2321) | ||||
| - TextUnformatted: Accept null ranges including (NULL,NULL) without asserting, in order to conform | ||||
|   to common idioms (e.g. passing .data(), .data() + .size() from a null string). (#3615) | ||||
| - Nav: Fixed toggling menu layer with Alt or exiting menu layer with Esc not moving mouse when | ||||
|   the NavEnableSetMousePos config flag is set. | ||||
| - Menus: adjust closing logic to accomodate for varying font size and dpi. | ||||
| - Drag and Drop: Fixed using BeginDragDropSource() inside a BeginChild() that returned false. (#4515) | ||||
| - PlotHistogram: Fixed zero-line position when manually specifying min<0 and max>0. (#4349) [@filippocrocchini] | ||||
| - IO: Added 'io.WantCaptureMouseUnlessPopupClose' alternative to `io.WantCaptureMouse'. (#4480) | ||||
|   This allows apps to receive the click on void when that click is used to close popup (by default, | ||||
|   clicking on a void when a popup is open will close the popup but not release io.WantCaptureMouse). | ||||
| - Fonts: imgui_freetype: Fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL | ||||
|   (which apparently happens with Freetype 2.11). (#4394, #4145?). | ||||
| - Fonts: Fixed ImFontAtlas::ClearInputData() marking atlas as not built. (#4455, #3487) | ||||
| - Backends: OpenGL3: Fixed our new GL loader conflicting with user using GL3W. (#4445) | ||||
| - Backends: OpenGL3: Fixed our custom GL loader conflicting with user using GL3W. (#4445) [@rokups] | ||||
| - Backends: WebGPU: Fixed for latest specs. (#4472) [@Kangz] | ||||
| - Backends: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted via | ||||
|   a direct unclipped PushClipRect() call. (#4464) | ||||
|   | ||||
| @@ -362,9 +362,10 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i | ||||
|  - nav: patterns to make it possible for arrows key to update selection (see JustMovedTo in range_select branch) | ||||
|  - nav: restore/find nearest NavId when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name) | ||||
|  - nav: SetItemDefaultFocus() level of priority, so widget like Selectable when inside a popup could claim a low-priority default focus on the first selected iem | ||||
|  - nav: NavFlattened: init requests don't work properly on flattened siblings. | ||||
|  - nav: NavFlattened: pageup/pagedown/home/end don't work properly on flattened siblings. | ||||
|  - nav: NavFlattened: ESC on a flattened child should select something. | ||||
|  - nav: NavFlattened: broken: in typical usage scenario, the items of a fully clipped child are currently not considered to enter into a NavFlattened child. | ||||
|  - nav: NavFlattened: init request doesn't select items that are part of a NavFlattened child | ||||
|  - nav: NavFlattened: cannot access menu-bar of a flattened child window with Alt/menu key (not a very common use case..). | ||||
|  - nav: simulate right-click or context activation? (SHIFT+F10) | ||||
|  - nav/tabbing: refactor old tabbing system and turn into navigation, should pass through all widgets (in submission order?). | ||||
|   | ||||
							
								
								
									
										366
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										366
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -923,15 +923,14 @@ namespace ImGui | ||||
| static void             NavUpdate(); | ||||
| static void             NavUpdateWindowing(); | ||||
| static void             NavUpdateWindowingOverlay(); | ||||
| static void             NavUpdateInitResult(); | ||||
| static void             NavUpdateCancelRequest(); | ||||
| static void             NavUpdateCreateMoveRequest(); | ||||
| static float            NavUpdatePageUpPageDown(); | ||||
| static inline void      NavUpdateAnyRequestFlag(); | ||||
| static void             NavEndFrame(); | ||||
| static bool             NavScoreItem(ImGuiNavItemData* result, ImRect cand); | ||||
| static void             NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel); | ||||
| static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); | ||||
| static bool             NavScoreItem(ImGuiNavItemData* result); | ||||
| static void             NavApplyItemToResult(ImGuiNavItemData* result); | ||||
| static void             NavProcessItem(); | ||||
| static ImVec2           NavCalcPreferredRefPos(); | ||||
| static void             NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); | ||||
| static ImGuiWindow*     NavRestoreLastChildNavWindow(ImGuiWindow* window); | ||||
| @@ -2294,21 +2293,21 @@ void ImGui::CalcListClipping(int items_count, float items_height, int* out_items | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect | ||||
|     // We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect | ||||
|     ImRect unclipped_rect = window->ClipRect; | ||||
|     if (g.NavMoveRequest) | ||||
|     if (g.NavMoveScoringItems) | ||||
|         unclipped_rect.Add(g.NavScoringRect); | ||||
|     if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) | ||||
|         unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max)); | ||||
|         unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max)); // Could store and use NavJustMovedToRectRel | ||||
|  | ||||
|     const ImVec2 pos = window->DC.CursorPos; | ||||
|     int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); | ||||
|     int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); | ||||
|  | ||||
|     // When performing a navigation request, ensure we have one item extra in the direction we are moving to | ||||
|     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) | ||||
|     if (g.NavMoveScoringItems && g.NavMoveClipDir == ImGuiDir_Up) | ||||
|         start--; | ||||
|     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) | ||||
|     if (g.NavMoveScoringItems && g.NavMoveClipDir == ImGuiDir_Down) | ||||
|         end++; | ||||
|  | ||||
|     start = ImClamp(start, 0, items_count); | ||||
| @@ -3154,7 +3153,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) | ||||
|     if (id) | ||||
|     { | ||||
|         g.ActiveIdIsAlive = id; | ||||
|         g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; | ||||
|         g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; | ||||
|     } | ||||
|  | ||||
|     // Clear declaration of inputs claimed by the widget | ||||
| @@ -3361,7 +3360,8 @@ void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemS | ||||
|  | ||||
| // Called by ItemAdd() | ||||
| // Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. | ||||
| void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id) | ||||
| // [WIP] This will eventually be refactored and moved into NavProcessItem() | ||||
| void ImGui::ItemInputable(ImGuiWindow* window, ImGuiID id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     IM_ASSERT(id != 0 && id == g.LastItemData.ID); | ||||
| @@ -3395,7 +3395,7 @@ void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id) | ||||
|         } | ||||
|         if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop) | ||||
|         { | ||||
|             g.NavJustTabbedId = id; | ||||
|             g.NavJustTabbedId = id; // FIXME-NAV: aim to eventually set in NavUpdate() once we finish the refactor | ||||
|             g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing; | ||||
|             return; | ||||
|         } | ||||
| @@ -3821,13 +3821,15 @@ static void ImGui::UpdateMouseInputs() | ||||
|  | ||||
|     // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) | ||||
|     if (IsMousePosValid(&g.IO.MousePos)) | ||||
|         g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); | ||||
|         g.IO.MousePos = g.MouseLastValidPos = ImFloor(g.IO.MousePos); | ||||
|  | ||||
|     // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta | ||||
|     if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) | ||||
|         g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; | ||||
|     else | ||||
|         g.IO.MouseDelta = ImVec2(0.0f, 0.0f); | ||||
|  | ||||
|     // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. | ||||
|     if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) | ||||
|         g.NavDisableMouseHover = false; | ||||
|  | ||||
| @@ -7066,7 +7068,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) | ||||
|         g.NavFocusScopeId = 0; | ||||
|         g.NavIdIsAlive = false; | ||||
|         g.NavLayer = ImGuiNavLayer_Main; | ||||
|         g.NavInitRequest = g.NavMoveRequest = false; | ||||
|         g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false; | ||||
|         NavUpdateAnyRequestFlag(); | ||||
|         //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); | ||||
|     } | ||||
| @@ -7656,6 +7658,7 @@ void ImGui::ActivateItem(ImGuiID id) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     g.NavNextActivateId = id; | ||||
|     g.NavNextActivateFlags = ImGuiActivateFlags_None; | ||||
| } | ||||
|  | ||||
| void ImGui::PushFocusScope(ImGuiID id) | ||||
| @@ -8124,15 +8127,17 @@ void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) | ||||
| // Declare item bounding box for clipping and interaction. | ||||
| // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface | ||||
| // declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. | ||||
| bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemAddFlags flags) | ||||
| bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|  | ||||
|     // Set item data | ||||
|     // (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set) | ||||
|     g.LastItemData.ID = id; | ||||
|     g.LastItemData.Rect = bb; | ||||
|     g.LastItemData.InFlags = g.CurrentItemFlags; | ||||
|     g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; | ||||
|     g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags; | ||||
|     g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; | ||||
|  | ||||
|     // Directional navigation processing | ||||
| @@ -8151,7 +8156,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu | ||||
|         if (g.NavId == id || g.NavAnyRequest) | ||||
|             if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) | ||||
|                 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) | ||||
|                     NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); | ||||
|                     NavProcessItem(); | ||||
|  | ||||
|         // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd() | ||||
| #ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX | ||||
| @@ -8175,10 +8180,10 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu | ||||
|         return false; | ||||
|     //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] | ||||
|  | ||||
|     // Tab stop handling (previously was using internal ItemFocusable() api) | ||||
|     // FIXME-NAV: We would now want to move this above the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343) | ||||
|     if (flags & ImGuiItemAddFlags_Focusable) | ||||
|         ItemFocusable(window, id); | ||||
|     // [WIP] Tab stop handling (previously was using internal FocusableItemRegister() api) | ||||
|     // FIXME-NAV: We would now want to move this before the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343) | ||||
|     if (extra_flags & ImGuiItemFlags_Inputable) | ||||
|         ItemInputable(window, id); | ||||
|  | ||||
|     // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) | ||||
|     if (IsMouseHoveringRect(bb.Min, bb.Max)) | ||||
| @@ -8444,6 +8449,7 @@ ImVec2 ImGui::GetWindowContentRegionMax() | ||||
|  | ||||
| // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) | ||||
| // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. | ||||
| // FIXME-OPT: Could we safely early out on ->SkipItems? | ||||
| void ImGui::BeginGroup() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -9324,6 +9330,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) | ||||
| //----------------------------------------------------------------------------- | ||||
|  | ||||
| // FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked. | ||||
| // In our terminology those should be interchangeable. Those two functions are merely a legacy artifact, so at minimum naming should be clarified. | ||||
| void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -9354,7 +9361,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) | ||||
|     g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; | ||||
|     window->NavLastIds[nav_layer] = id; | ||||
|     if (g.LastItemData.ID == id) | ||||
|         window->NavRectRel[nav_layer] = ImRect(g.LastItemData.Rect.Min - window->Pos, g.LastItemData.Rect.Max - window->Pos); | ||||
|         window->NavRectRel[nav_layer] = ImRect(g.LastItemData.NavRect.Min - window->Pos, g.LastItemData.NavRect.Max - window->Pos); | ||||
|  | ||||
|     if (g.ActiveIdSource == ImGuiInputSource_Nav) | ||||
|         g.NavDisableMouseHover = true; | ||||
| @@ -9385,7 +9392,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect | ||||
|         r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); | ||||
|         r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); | ||||
|     } | ||||
|     else | ||||
|     else // FIXME: PageUp/PageDown are leaving move_dir == None | ||||
|     { | ||||
|         r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); | ||||
|         r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); | ||||
| @@ -9393,15 +9400,17 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect | ||||
| } | ||||
|  | ||||
| // Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 | ||||
| static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand) | ||||
| static bool ImGui::NavScoreItem(ImGuiNavItemData* result) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     if (g.NavLayer != window->DC.NavLayerCurrent) | ||||
|         return false; | ||||
|  | ||||
|     const ImRect& curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) | ||||
|     g.NavScoringCount++; | ||||
|     // FIXME: Those are not good variables names | ||||
|     ImRect cand = g.LastItemData.NavRect;   // Current item nav rectangle | ||||
|     const ImRect curr = g.NavScoringRect;   // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) | ||||
|     g.NavScoringDebugCount++; | ||||
|  | ||||
|     // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring | ||||
|     if (window->ParentWindow == g.NavWindow) | ||||
| @@ -9463,24 +9472,24 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand) | ||||
|         draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); | ||||
|         draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); | ||||
|         draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150)); | ||||
|         draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); | ||||
|         draw_list->AddText(cand.Max, ~0U, buf); | ||||
|     } | ||||
|     else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. | ||||
|     { | ||||
|         if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } | ||||
|         if (quadrant == g.NavMoveDir) | ||||
|         { | ||||
|             ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); | ||||
|             ImDrawList* draw_list = GetForegroundDrawList(window); | ||||
|             draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); | ||||
|             draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); | ||||
|             draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     // Is it in the quadrant we're interesting in moving to? | ||||
|     bool new_best = false; | ||||
|     if (quadrant == g.NavMoveDir) | ||||
|     const ImGuiDir move_dir = g.NavMoveDir; | ||||
|     if (quadrant == move_dir) | ||||
|     { | ||||
|         // Does it beat the current best candidate? | ||||
|         if (dist_box < result->DistBox) | ||||
| @@ -9502,7 +9511,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand) | ||||
|                 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items | ||||
|                 // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), | ||||
|                 // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. | ||||
|                 if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance | ||||
|                 if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance | ||||
|                     new_best = true; | ||||
|             } | ||||
|         } | ||||
| @@ -9515,7 +9524,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand) | ||||
|     // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? | ||||
|     if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match | ||||
|         if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|             if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) | ||||
|             if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f)) | ||||
|             { | ||||
|                 result->DistAxial = dist_axial; | ||||
|                 new_best = true; | ||||
| @@ -9524,23 +9533,25 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand) | ||||
|     return new_best; | ||||
| } | ||||
|  | ||||
| static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel) | ||||
| static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     result->Window = window; | ||||
|     result->ID = id; | ||||
|     result->ID = g.LastItemData.ID; | ||||
|     result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; | ||||
|     result->RectRel = nav_bb_rel; | ||||
|     result->RectRel = ImRect(g.LastItemData.NavRect.Min - window->Pos, g.LastItemData.NavRect.Max - window->Pos); | ||||
| } | ||||
|  | ||||
| // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) | ||||
| static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) | ||||
| // This is called after LastItemData is set. | ||||
| static void ImGui::NavProcessItem() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     //if (!g.IO.NavActive)  // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. | ||||
|     //    return; | ||||
|  | ||||
|     ImGuiWindow* window = g.CurrentWindow; | ||||
|     const ImGuiID id = g.LastItemData.ID; | ||||
|     const ImRect nav_bb = g.LastItemData.NavRect; | ||||
|     const ImGuiItemFlags item_flags = g.LastItemData.InFlags; | ||||
|     const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); | ||||
|  | ||||
|     // Process Init Request | ||||
|     if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) | ||||
| @@ -9550,7 +9561,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con | ||||
|         if (candidate_for_nav_default_focus || g.NavInitResultId == 0) | ||||
|         { | ||||
|             g.NavInitResultId = id; | ||||
|             g.NavInitResultRectRel = nav_bb_rel; | ||||
|             g.NavInitResultRectRel = ImRect(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); | ||||
|         } | ||||
|         if (candidate_for_nav_default_focus) | ||||
|         { | ||||
| @@ -9560,27 +9571,22 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con | ||||
|     } | ||||
|  | ||||
|     // Process Move Request (scoring for navigation) | ||||
|     // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) | ||||
|     if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav))) | ||||
|     // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy) | ||||
|     if (g.NavMoveScoringItems) | ||||
|     { | ||||
|         ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; | ||||
| #if IMGUI_DEBUG_NAV_SCORING | ||||
|         // [DEBUG] Score all items in NavWindow at all times | ||||
|         if (!g.NavMoveRequest) | ||||
|             g.NavMoveDir = g.NavMoveDirLast; | ||||
|         bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; | ||||
| #else | ||||
|         bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); | ||||
| #endif | ||||
|         if (new_best) | ||||
|             NavApplyItemToResult(result, window, id, nav_bb_rel); | ||||
|         if ((g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav))) | ||||
|         { | ||||
|             ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; | ||||
|             if (NavScoreItem(result)) | ||||
|                 NavApplyItemToResult(result); | ||||
|  | ||||
|         // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. | ||||
|         const float VISIBLE_RATIO = 0.70f; | ||||
|         if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) | ||||
|             if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) | ||||
|                 if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) | ||||
|                     NavApplyItemToResult(&g.NavMoveResultLocalVisibleSet, window, id, nav_bb_rel); | ||||
|             // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. | ||||
|             const float VISIBLE_RATIO = 0.70f; | ||||
|             if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) | ||||
|                 if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) | ||||
|                     if (NavScoreItem(&g.NavMoveResultLocalVisible)) | ||||
|                         NavApplyItemToResult(&g.NavMoveResultLocalVisible); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Update window-relative bounding box of navigated item | ||||
| @@ -9590,20 +9596,38 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con | ||||
|         g.NavLayer = window->DC.NavLayerCurrent; | ||||
|         g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; | ||||
|         g.NavIdIsAlive = true; | ||||
|         window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position) | ||||
|         window->NavRectRel[window->DC.NavLayerCurrent] = ImRect(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);    // Store item bounding box (relative to window position) | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool ImGui::NavMoveRequestButNoResultYet() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; | ||||
|     return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; | ||||
| } | ||||
|  | ||||
| // FIXME: ScoringRect is not set | ||||
| void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     IM_ASSERT(g.NavWindow != NULL); | ||||
|     g.NavMoveSubmitted = g.NavMoveScoringItems = true; | ||||
|     g.NavMoveDir = move_dir; | ||||
|     g.NavMoveDirForDebug = move_dir; | ||||
|     g.NavMoveClipDir = clip_dir; | ||||
|     g.NavMoveFlags = move_flags; | ||||
|     g.NavMoveForwardToNextFrame = false; | ||||
|     g.NavMoveKeyMods = g.IO.KeyMods; | ||||
|     g.NavMoveResultLocal.Clear(); | ||||
|     g.NavMoveResultLocalVisible.Clear(); | ||||
|     g.NavMoveResultOther.Clear(); | ||||
|     NavUpdateAnyRequestFlag(); | ||||
| } | ||||
|  | ||||
| void ImGui::NavMoveRequestCancel() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     g.NavMoveRequest = false; | ||||
|     g.NavMoveSubmitted = g.NavMoveScoringItems = false; | ||||
|     NavUpdateAnyRequestFlag(); | ||||
| } | ||||
|  | ||||
| @@ -9611,12 +9635,12 @@ void ImGui::NavMoveRequestCancel() | ||||
| void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     IM_ASSERT(g.NavMoveRequestForwardToNextFrame == false); | ||||
|     IM_ASSERT(g.NavMoveForwardToNextFrame == false); | ||||
|     NavMoveRequestCancel(); | ||||
|     g.NavMoveRequestForwardToNextFrame = true; | ||||
|     g.NavMoveForwardToNextFrame = true; | ||||
|     g.NavMoveDir = move_dir; | ||||
|     g.NavMoveClipDir = clip_dir; | ||||
|     g.NavMoveRequestFlags = move_flags | ImGuiNavMoveFlags_Forwarded; | ||||
|     g.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded; | ||||
| } | ||||
|  | ||||
| // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire | ||||
| @@ -9625,8 +9649,9 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wra | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY | ||||
|     if (g.NavWindow == window && g.NavMoveRequest && g.NavLayer == ImGuiNavLayer_Main) | ||||
|         g.NavMoveRequestFlags |= wrap_flags; | ||||
|     // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it, NavEndFrame() will do the same test | ||||
|     if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main) | ||||
|         g.NavMoveFlags |= wrap_flags; | ||||
| } | ||||
|  | ||||
| // FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). | ||||
| @@ -9661,20 +9686,20 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer) | ||||
|     if (window->NavLastIds[layer] != 0) | ||||
|     { | ||||
|         SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); | ||||
|         g.NavDisableHighlight = false; | ||||
|         g.NavDisableMouseHover = g.NavMousePosDirty = true; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         g.NavLayer = layer; | ||||
|         NavInitWindow(window, true); | ||||
|     } | ||||
|     g.NavDisableHighlight = false; | ||||
|     g.NavDisableMouseHover = g.NavMousePosDirty = true; | ||||
| } | ||||
|  | ||||
| static inline void ImGui::NavUpdateAnyRequestFlag() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); | ||||
|     g.NavAnyRequest = g.NavMoveScoringItems || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); | ||||
|     if (g.NavAnyRequest) | ||||
|         IM_ASSERT(g.NavWindow != NULL); | ||||
| } | ||||
| @@ -9720,7 +9745,7 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() | ||||
|         // Mouse (we need a fallback in case the mouse becomes invalid after being used) | ||||
|         if (IsMousePosValid(&g.IO.MousePos)) | ||||
|             return g.IO.MousePos; | ||||
|         return g.LastValidMousePos; | ||||
|         return g.MouseLastValidPos; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| @@ -9776,9 +9801,7 @@ static void ImGui::NavUpdate() | ||||
|     ImGuiIO& io = g.IO; | ||||
|  | ||||
|     io.WantSetMousePos = false; | ||||
| #if 0 | ||||
|     if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); | ||||
| #endif | ||||
|     //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); | ||||
|  | ||||
|     // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard) | ||||
|     // (do it before we map Keyboard input!) | ||||
| @@ -9814,16 +9837,16 @@ static void ImGui::NavUpdate() | ||||
|  | ||||
|     // Process navigation init request (select first/default focus) | ||||
|     if (g.NavInitResultId != 0) | ||||
|         NavUpdateInitResult(); | ||||
|         NavInitRequestApplyResult(); | ||||
|     g.NavInitRequest = false; | ||||
|     g.NavInitRequestFromMove = false; | ||||
|     g.NavInitResultId = 0; | ||||
|     g.NavJustMovedToId = 0; | ||||
|  | ||||
|     // Process navigation move request | ||||
|     if (g.NavMoveRequest) | ||||
|     if (g.NavMoveSubmitted) | ||||
|         NavMoveRequestApplyResult(); | ||||
|     g.NavMoveRequest = false; | ||||
|     g.NavMoveSubmitted = g.NavMoveScoringItems = false; | ||||
|  | ||||
|     // Apply application mouse position movement, after we had a chance to process move request result. | ||||
|     if (g.NavMousePosDirty && g.NavIdIsAlive) | ||||
| @@ -9834,6 +9857,7 @@ static void ImGui::NavUpdate() | ||||
|             { | ||||
|                 io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); | ||||
|                 io.WantSetMousePos = true; | ||||
|                 //IMGUI_DEBUG_LOG("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); | ||||
|             } | ||||
|         g.NavMousePosDirty = false; | ||||
|     } | ||||
| @@ -9858,19 +9882,28 @@ static void ImGui::NavUpdate() | ||||
|     NavUpdateCancelRequest(); | ||||
|  | ||||
|     // Process manual activation request | ||||
|     g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; | ||||
|     g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavActivateInputId = 0; | ||||
|     g.NavActivateFlags = ImGuiActivateFlags_None; | ||||
|     if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) | ||||
|     { | ||||
|         bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); | ||||
|         bool input_down = IsNavInputDown(ImGuiNavInput_Input); | ||||
|         bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); | ||||
|         bool input_pressed = input_down && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); | ||||
|         if (g.ActiveId == 0 && activate_pressed) | ||||
|         { | ||||
|             g.NavActivateId = g.NavId; | ||||
|             g.NavActivateFlags = ImGuiActivateFlags_PreferTweak; | ||||
|         } | ||||
|         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed) | ||||
|         { | ||||
|             g.NavActivateInputId = g.NavId; | ||||
|             g.NavActivateFlags = ImGuiActivateFlags_PreferInput; | ||||
|         } | ||||
|         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) | ||||
|             g.NavActivateDownId = g.NavId; | ||||
|         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) | ||||
|             g.NavActivatePressedId = g.NavId; | ||||
|         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) | ||||
|             g.NavInputId = g.NavId; | ||||
|     } | ||||
|     if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) | ||||
|         g.NavDisableHighlight = true; | ||||
| @@ -9878,8 +9911,15 @@ static void ImGui::NavUpdate() | ||||
|         IM_ASSERT(g.NavActivateDownId == g.NavActivateId); | ||||
|  | ||||
|     // Process programmatic activation request | ||||
|     // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others) | ||||
|     if (g.NavNextActivateId != 0) | ||||
|         g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; | ||||
|     { | ||||
|         if (g.NavNextActivateFlags & ImGuiActivateFlags_PreferInput) | ||||
|             g.NavActivateInputId = g.NavNextActivateId; | ||||
|         else | ||||
|             g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId; | ||||
|         g.NavActivateFlags = g.NavNextActivateFlags; | ||||
|     } | ||||
|     g.NavNextActivateId = 0; | ||||
|  | ||||
|     // Process move requests | ||||
| @@ -9892,12 +9932,13 @@ static void ImGui::NavUpdate() | ||||
|         // *Fallback* manual-scroll with Nav directional keys when window has no navigable item | ||||
|         ImGuiWindow* window = g.NavWindow; | ||||
|         const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. | ||||
|         if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) //-V560 | ||||
|         const ImGuiDir move_dir = g.NavMoveDir; | ||||
|         if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && move_dir != ImGuiDir_None) | ||||
|         { | ||||
|             if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) | ||||
|                 SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); | ||||
|             if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) | ||||
|                 SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); | ||||
|             if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) | ||||
|                 SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); | ||||
|             if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) | ||||
|                 SetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); | ||||
|         } | ||||
|  | ||||
|         // *Normal* Manual scroll with NavScrollXXX keys | ||||
| @@ -9909,8 +9950,15 @@ static void ImGui::NavUpdate() | ||||
|             SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); | ||||
|     } | ||||
|  | ||||
|     // Always prioritize mouse highlight if navigation is disabled | ||||
|     if (!nav_keyboard_active && !nav_gamepad_active) | ||||
|     { | ||||
|         g.NavDisableHighlight = true; | ||||
|         g.NavDisableMouseHover = g.NavMousePosDirty = false; | ||||
|     } | ||||
|  | ||||
|     // [DEBUG] | ||||
|     g.NavScoringCount = 0; | ||||
|     g.NavScoringDebugCount = 0; | ||||
| #if IMGUI_DEBUG_NAV_RECTS | ||||
|     if (g.NavWindow) | ||||
|     { | ||||
| @@ -9921,7 +9969,7 @@ static void ImGui::NavUpdate() | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void ImGui::NavUpdateInitResult() | ||||
| void ImGui::NavInitRequestApplyResult() | ||||
| { | ||||
|     // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -9932,6 +9980,7 @@ static void ImGui::NavUpdateInitResult() | ||||
|     // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently. | ||||
|     IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); | ||||
|     SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); | ||||
|     g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result | ||||
|     if (g.NavInitRequestFromMove) | ||||
|     { | ||||
|         g.NavDisableHighlight = false; | ||||
| @@ -9945,20 +9994,19 @@ void ImGui::NavUpdateCreateMoveRequest() | ||||
|     ImGuiIO& io = g.IO; | ||||
|     ImGuiWindow* window = g.NavWindow; | ||||
|  | ||||
|     if (g.NavMoveRequestForwardToNextFrame) | ||||
|     if (g.NavMoveForwardToNextFrame && window != NULL) | ||||
|     { | ||||
|         // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) | ||||
|         // (preserve most state, which were already set by the NavMoveRequestForward() function) | ||||
|         IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); | ||||
|         IM_ASSERT(g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded); | ||||
|         IM_ASSERT(g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded); | ||||
|         IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); | ||||
|         g.NavMoveRequestForwardToNextFrame = false; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Initiate directional inputs request | ||||
|         g.NavMoveDir = ImGuiDir_None; | ||||
|         g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; | ||||
|         g.NavMoveFlags = ImGuiNavMoveFlags_None; | ||||
|         if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs)) | ||||
|         { | ||||
|             const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; | ||||
| @@ -9973,24 +10021,28 @@ void ImGui::NavUpdateCreateMoveRequest() | ||||
|     // Update PageUp/PageDown/Home/End scroll | ||||
|     // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? | ||||
|     const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; | ||||
|     float nav_scoring_rect_offset_y = 0.0f; | ||||
|     if (nav_keyboard_active) | ||||
|         nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(); | ||||
|     float scoring_rect_offset_y = 0.0f; | ||||
|     if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active) | ||||
|         scoring_rect_offset_y = NavUpdatePageUpPageDown(); | ||||
|  | ||||
|     // If we initiate a movement request and have no current NavId, we initiate a InitDefaultRequest that will be used as a fallback if the direction fails to find a match | ||||
|     if (g.NavMoveDir != ImGuiDir_None) | ||||
|     // [DEBUG] Always send a request | ||||
| #if IMGUI_DEBUG_NAV_SCORING | ||||
|     if (io.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) | ||||
|         g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); | ||||
|     if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None) | ||||
|     { | ||||
|         IM_ASSERT(window != NULL); | ||||
|         g.NavMoveRequest = true; | ||||
|         g.NavMoveRequestKeyMods = io.KeyMods; | ||||
|         g.NavMoveDirLast = g.NavMoveDir; | ||||
|         g.NavMoveResultLocal.Clear(); | ||||
|         g.NavMoveResultLocalVisibleSet.Clear(); | ||||
|         g.NavMoveResultOther.Clear(); | ||||
|         g.NavMoveDir = g.NavMoveDirForDebug; | ||||
|         g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     // Moving with no reference triggers a init request | ||||
|     if (g.NavMoveRequest && g.NavId == 0) | ||||
|     // Submit | ||||
|     g.NavMoveForwardToNextFrame = false; | ||||
|     if (g.NavMoveDir != ImGuiDir_None) | ||||
|         NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags); | ||||
|  | ||||
|     // Moving with no reference triggers a init request (will be used as a fallback if the direction fails to find a match) | ||||
|     if (g.NavMoveSubmitted && g.NavId == 0) | ||||
|     { | ||||
|         IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); | ||||
|         g.NavInitRequest = g.NavInitRequestFromMove = true; | ||||
| @@ -10001,7 +10053,7 @@ void ImGui::NavUpdateCreateMoveRequest() | ||||
|     // When using gamepad, we project the reference nav bounding box into window visible area. | ||||
|     // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative | ||||
|     // (can't focus a visible object like we can with the mouse). | ||||
|     if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL) | ||||
|     if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL) | ||||
|     { | ||||
|         ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); | ||||
|         if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) | ||||
| @@ -10015,27 +10067,35 @@ void ImGui::NavUpdateCreateMoveRequest() | ||||
|     } | ||||
|  | ||||
|     // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) | ||||
|     g.NavScoringRect = ImRect(); | ||||
|     if (window) | ||||
|     ImRect scoring_rect; | ||||
|     if (window != NULL) | ||||
|     { | ||||
|         ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); | ||||
|         g.NavScoringRect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max); | ||||
|         g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y); | ||||
|         g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x); | ||||
|         g.NavScoringRect.Max.x = g.NavScoringRect.Min.x; | ||||
|         IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). | ||||
|         //GetForegroundDrawList()->AddRect(g.NavScoringRect.Min, g.NavScoringRect.Max, IM_COL32(255,200,0,255)); // [DEBUG] | ||||
|         scoring_rect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max); | ||||
|         scoring_rect.TranslateY(scoring_rect_offset_y); | ||||
|         scoring_rect.Min.x = ImMin(scoring_rect.Min.x + 1.0f, scoring_rect.Max.x); | ||||
|         scoring_rect.Max.x = scoring_rect.Min.x; | ||||
|         IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). | ||||
|         //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] | ||||
|     } | ||||
|     g.NavScoringRect = scoring_rect; | ||||
| } | ||||
|  | ||||
| // Apply result from previous frame navigation directional move request. Always called from NavUpdate() | ||||
| void ImGui::NavMoveRequestApplyResult() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| #if IMGUI_DEBUG_NAV_SCORING | ||||
|     if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times | ||||
|         return; | ||||
| #endif | ||||
|  | ||||
|     if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) | ||||
|     // Select which result to use | ||||
|     ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL; | ||||
|  | ||||
|     // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) | ||||
|     if (result == NULL) | ||||
|     { | ||||
|         // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) | ||||
|         if (g.NavId != 0) | ||||
|         { | ||||
|             g.NavDisableHighlight = false; | ||||
| @@ -10044,13 +10104,10 @@ void ImGui::NavMoveRequestApplyResult() | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Select which result to use | ||||
|     ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; | ||||
|  | ||||
|     // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. | ||||
|     if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) | ||||
|         if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) | ||||
|             result = &g.NavMoveResultLocalVisibleSet; | ||||
|     if (g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) | ||||
|         if (g.NavMoveResultLocalVisible.ID != 0 && g.NavMoveResultLocalVisible.ID != g.NavId) | ||||
|             result = &g.NavMoveResultLocalVisible; | ||||
|  | ||||
|     // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. | ||||
|     if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) | ||||
| @@ -10062,7 +10119,7 @@ void ImGui::NavMoveRequestApplyResult() | ||||
|     if (g.NavLayer == ImGuiNavLayer_Main) | ||||
|     { | ||||
|         ImVec2 delta_scroll; | ||||
|         if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge) | ||||
|         if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdge) | ||||
|         { | ||||
|             float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; | ||||
|             delta_scroll.y = result->Window->Scroll.y - scroll_target; | ||||
| @@ -10086,10 +10143,14 @@ void ImGui::NavMoveRequestApplyResult() | ||||
|         // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) | ||||
|         g.NavJustMovedToId = result->ID; | ||||
|         g.NavJustMovedToFocusScopeId = result->FocusScopeId; | ||||
|         g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods; | ||||
|         g.NavJustMovedToKeyMods = g.NavMoveKeyMods; | ||||
|     } | ||||
|  | ||||
|     // Focus | ||||
|     IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); | ||||
|     SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); | ||||
|  | ||||
|     // Enable nav highlight | ||||
|     g.NavDisableHighlight = false; | ||||
|     g.NavDisableMouseHover = g.NavMousePosDirty = true; | ||||
| } | ||||
| @@ -10141,18 +10202,18 @@ static void ImGui::NavUpdateCancelRequest() | ||||
| } | ||||
|  | ||||
| // Handle PageUp/PageDown/Home/End keys | ||||
| // Called from NavUpdateCreateMoveRequest() which will use our output to create a move request | ||||
| // FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference | ||||
| // FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid? | ||||
| static float ImGui::NavUpdatePageUpPageDown() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiIO& io = g.IO; | ||||
|  | ||||
|     if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL) | ||||
|         return 0.0f; | ||||
|     if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main) | ||||
|     ImGuiWindow* window = g.NavWindow; | ||||
|     if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main) | ||||
|         return 0.0f; | ||||
|  | ||||
|     ImGuiWindow* window = g.NavWindow; | ||||
|     const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); | ||||
|     const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); | ||||
|     const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); | ||||
| @@ -10182,14 +10243,14 @@ static float ImGui::NavUpdatePageUpPageDown() | ||||
|             nav_scoring_rect_offset_y = -page_offset_y; | ||||
|             g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) | ||||
|             g.NavMoveClipDir = ImGuiDir_Up; | ||||
|             g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; | ||||
|             g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; | ||||
|         } | ||||
|         else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) | ||||
|         { | ||||
|             nav_scoring_rect_offset_y = +page_offset_y; | ||||
|             g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) | ||||
|             g.NavMoveClipDir = ImGuiDir_Down; | ||||
|             g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; | ||||
|             g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; | ||||
|         } | ||||
|         else if (home_pressed) | ||||
|         { | ||||
| @@ -10200,7 +10261,8 @@ static float ImGui::NavUpdatePageUpPageDown() | ||||
|             if (nav_rect_rel.IsInverted()) | ||||
|                 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; | ||||
|             g.NavMoveDir = ImGuiDir_Down; | ||||
|             g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; | ||||
|             g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; | ||||
|             // FIXME-NAV: MoveClipDir left to _None, intentional? | ||||
|         } | ||||
|         else if (end_pressed) | ||||
|         { | ||||
| @@ -10208,7 +10270,8 @@ static float ImGui::NavUpdatePageUpPageDown() | ||||
|             if (nav_rect_rel.IsInverted()) | ||||
|                 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; | ||||
|             g.NavMoveDir = ImGuiDir_Up; | ||||
|             g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; | ||||
|             g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; | ||||
|             // FIXME-NAV: MoveClipDir left to _None, intentional? | ||||
|         } | ||||
|         return nav_scoring_rect_offset_y; | ||||
|     } | ||||
| @@ -10226,9 +10289,9 @@ static void ImGui::NavEndFrame() | ||||
|     // Perform wrap-around in menus | ||||
|     // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame. | ||||
|     ImGuiWindow* window = g.NavWindow; | ||||
|     const ImGuiNavMoveFlags move_flags = g.NavMoveRequestFlags; | ||||
|     const ImGuiNavMoveFlags move_flags = g.NavMoveFlags; | ||||
|     const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY; | ||||
|     if (window && NavMoveRequestButNoResultYet() && (g.NavMoveRequestFlags & wanted_flags) && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0) | ||||
|     if (window && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & wanted_flags) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) | ||||
|     { | ||||
|         bool do_forward = false; | ||||
|         ImRect bb_rel = window->NavRectRel[g.NavLayer]; | ||||
| @@ -10484,15 +10547,17 @@ static void ImGui::NavUpdateWindowing() | ||||
|             FocusWindow(new_nav_window); | ||||
|             new_nav_window->NavLastChildNavWindow = old_nav_window; | ||||
|         } | ||||
|         g.NavDisableHighlight = false; | ||||
|         g.NavDisableMouseHover = true; | ||||
|  | ||||
|         // Reinitialize navigation when entering menu bar with the Alt key. | ||||
|         // Toggle layer | ||||
|         const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; | ||||
|         const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL); | ||||
|         if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id) | ||||
|             g.NavWindow->NavLastIds[new_nav_layer] = 0; | ||||
|         NavRestoreLayer(new_nav_layer); | ||||
|         if (new_nav_layer != g.NavLayer) | ||||
|         { | ||||
|             // Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?) | ||||
|             const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL); | ||||
|             if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id) | ||||
|                 g.NavWindow->NavLastIds[new_nav_layer] = 0; | ||||
|             NavRestoreLayer(new_nav_layer); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -10587,14 +10652,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) | ||||
|                 return false; | ||||
|             if (g.ActiveIdMouseButton != -1) | ||||
|                 mouse_button = g.ActiveIdMouseButton; | ||||
|             if (g.IO.MouseDown[mouse_button] == false) | ||||
|             if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) | ||||
|                 return false; | ||||
|             g.ActiveIdAllowOverlap = false; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Uncommon path: items without ID | ||||
|             if (g.IO.MouseDown[mouse_button] == false) | ||||
|             if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) | ||||
|                 return false; | ||||
|             if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) | ||||
|                 return false; | ||||
|  | ||||
|             // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: | ||||
| @@ -10605,10 +10672,6 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             // Early out | ||||
|             if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) | ||||
|                 return false; | ||||
|  | ||||
|             // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() | ||||
|             // We build a throwaway ID based on current ID stack + relative AABB of items in window. | ||||
|             // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. | ||||
| @@ -10774,7 +10837,7 @@ bool ImGui::BeginDragDropTarget() | ||||
|     if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect)) | ||||
|         return false; | ||||
|     ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; | ||||
|     if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree) | ||||
|     if (hovered_window == NULL || window->RootWindowDockTree != hovered_window->RootWindowDockTree || window->SkipItems) | ||||
|         return false; | ||||
|  | ||||
|     const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect; | ||||
| @@ -16716,7 +16779,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) | ||||
|         Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); | ||||
|         Text("NavInputSource: %s", input_source_names[g.NavInputSource]); | ||||
|         Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); | ||||
|         Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); | ||||
|         Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId); | ||||
|         Text("NavActivateFlags: %04X", g.NavActivateFlags); | ||||
|         Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); | ||||
|         Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); | ||||
|         Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); | ||||
|   | ||||
							
								
								
									
										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.85 WIP" | ||||
| #define IMGUI_VERSION_NUM           18410 | ||||
| #define IMGUI_VERSION_NUM           18412 | ||||
| #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 | ||||
|   | ||||
| @@ -1613,16 +1613,17 @@ static void ShowDemoWindowWidgets() | ||||
|     } | ||||
|  | ||||
|     // Plot/Graph widgets are not very good. | ||||
|     // Consider writing your own, or using a third-party one, see: | ||||
|     // - ImPlot https://github.com/epezent/implot | ||||
|     // - others https://github.com/ocornut/imgui/wiki/Useful-Extensions | ||||
|     // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot | ||||
|     // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) | ||||
|     if (ImGui::TreeNode("Plots Widgets")) | ||||
|     { | ||||
|         static bool animate = true; | ||||
|         ImGui::Checkbox("Animate", &animate); | ||||
|  | ||||
|         // Plot as lines and plot as histogram | ||||
|         static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; | ||||
|         ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); | ||||
|         ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); | ||||
|  | ||||
|         // Fill an array of contiguous float values to plot | ||||
|         // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float | ||||
| @@ -1652,7 +1653,6 @@ static void ShowDemoWindowWidgets() | ||||
|             sprintf(overlay, "avg %f", average); | ||||
|             ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); | ||||
|         } | ||||
|         ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); | ||||
|  | ||||
|         // Use functions to generate output | ||||
|         // FIXME: This is rather awkward because current plot API only pass in indices. | ||||
|   | ||||
| @@ -148,8 +148,8 @@ struct ImGuiWindowSettings;         // Storage for a window .ini settings (we ke | ||||
| // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. | ||||
| typedef int ImGuiDataAuthority;         // -> enum ImGuiDataAuthority_      // Enum: for storing the source authority (dock node vs window) of a field | ||||
| typedef int ImGuiLayoutType;            // -> enum ImGuiLayoutType_         // Enum: Horizontal or vertical | ||||
| typedef int ImGuiActivateFlags;         // -> enum ImGuiActivateFlags_      // Flags: for navigation/focus function (will be for ActivateItem() later) | ||||
| typedef int ImGuiItemFlags;             // -> enum ImGuiItemFlags_          // Flags: for PushItemFlag() | ||||
| typedef int ImGuiItemAddFlags;          // -> enum ImGuiItemAddFlags_       // Flags: for ItemAdd() | ||||
| typedef int ImGuiItemStatusFlags;       // -> enum ImGuiItemStatusFlags_    // Flags: for DC.LastItemStatusFlags | ||||
| typedef int ImGuiOldColumnFlags;        // -> enum ImGuiOldColumnFlags_     // Flags: for BeginColumns() | ||||
| typedef int ImGuiNavHighlightFlags;     // -> enum ImGuiNavHighlightFlags_  // Flags: for RenderNavHighlight() | ||||
| @@ -754,15 +754,8 @@ enum ImGuiItemFlags_ | ||||
|     ImGuiItemFlags_NoNavDefaultFocus        = 1 << 4,  // false     // Disable item being a candidate for default focus (e.g. used by title bar items) | ||||
|     ImGuiItemFlags_SelectableDontClosePopup = 1 << 5,  // false     // Disable MenuItem/Selectable() automatically closing their popup window | ||||
|     ImGuiItemFlags_MixedValue               = 1 << 6,  // false     // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) | ||||
|     ImGuiItemFlags_ReadOnly                 = 1 << 7   // false     // [ALPHA] Allow hovering interactions but underlying value is not changed. | ||||
| }; | ||||
|  | ||||
| // Flags for ItemAdd() | ||||
| // FIXME-NAV: _Focusable is _ALMOST_ what you would expect to be called '_TabStop' but because SetKeyboardFocusHere() works on items with no TabStop we distinguish Focusable from TabStop. | ||||
| enum ImGuiItemAddFlags_ | ||||
| { | ||||
|     ImGuiItemAddFlags_None                  = 0, | ||||
|     ImGuiItemAddFlags_Focusable             = 1 << 0    // FIXME-NAV: In current/legacy scheme, Focusable+TabStop support are opt-in by widgets. We will transition it toward being opt-out, so this flag is expected to eventually disappear. | ||||
|     ImGuiItemFlags_ReadOnly                 = 1 << 7,  // false     // [ALPHA] Allow hovering interactions but underlying value is not changed. | ||||
|     ImGuiItemFlags_Inputable                = 1 << 8   // false     // [WIP] Auto-activate item when focused. Currently only used and supported by a few items before it becomes a generic feature. | ||||
| }; | ||||
|  | ||||
| // Storage for LastItem data | ||||
| @@ -770,7 +763,7 @@ enum ImGuiItemStatusFlags_ | ||||
| { | ||||
|     ImGuiItemStatusFlags_None               = 0, | ||||
|     ImGuiItemStatusFlags_HoveredRect        = 1 << 0,   // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test) | ||||
|     ImGuiItemStatusFlags_HasDisplayRect     = 1 << 1,   // window->DC.LastItemDisplayRect is valid | ||||
|     ImGuiItemStatusFlags_HasDisplayRect     = 1 << 1,   // g.LastItemData.DisplayRect is valid | ||||
|     ImGuiItemStatusFlags_Edited             = 1 << 2,   // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) | ||||
|     ImGuiItemStatusFlags_ToggledSelection   = 1 << 3,   // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected", only state changes, in order to easily handle clipping with less issues. | ||||
|     ImGuiItemStatusFlags_ToggledOpen        = 1 << 4,   // Set when TreeNode() reports toggling their open state. | ||||
| @@ -1143,8 +1136,9 @@ struct ImGuiLastItemData | ||||
|     ImGuiID                 ID; | ||||
|     ImGuiItemFlags          InFlags;            // See ImGuiItemFlags_ | ||||
|     ImGuiItemStatusFlags    StatusFlags;        // See ImGuiItemStatusFlags_ | ||||
|     ImRect                  Rect; | ||||
|     ImRect                  DisplayRect; | ||||
|     ImRect                  Rect;               // Full rectangle | ||||
|     ImRect                  NavRect;            // Navigation scoring rectangle (not displayed) | ||||
|     ImRect                  DisplayRect;        // Display rectangle (only if ImGuiItemStatusFlags_HasDisplayRect is set) | ||||
|  | ||||
|     ImGuiLastItemData()     { memset(this, 0, sizeof(*this)); } | ||||
| }; | ||||
| @@ -1175,6 +1169,14 @@ struct ImGuiPtrOrIndex | ||||
| // [SECTION] Navigation support | ||||
| //----------------------------------------------------------------------------- | ||||
|  | ||||
| enum ImGuiActivateFlags_ | ||||
| { | ||||
|     ImGuiActivateFlags_None                 = 0, | ||||
|     ImGuiActivateFlags_PreferInput          = 1 << 0,       // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default if keyboard is available. | ||||
|     ImGuiActivateFlags_PreferTweak          = 1 << 1,       // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default if keyboard is not available. | ||||
|     ImGuiActivateFlags_TryToPreserveState   = 1 << 2        // Request widget to preserve state if it can (e.g. InputText will try to preserve cursor/selection) | ||||
| }; | ||||
|  | ||||
| enum ImGuiNavHighlightFlags_ | ||||
| { | ||||
|     ImGuiNavHighlightFlags_None             = 0, | ||||
| @@ -1200,9 +1202,10 @@ enum ImGuiNavMoveFlags_ | ||||
|     ImGuiNavMoveFlags_WrapX                 = 1 << 2,   // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) | ||||
|     ImGuiNavMoveFlags_WrapY                 = 1 << 3,   // This is not super useful but provided for completeness | ||||
|     ImGuiNavMoveFlags_AllowCurrentNavId     = 1 << 4,   // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) | ||||
|     ImGuiNavMoveFlags_AlsoScoreVisibleSet   = 1 << 5,   // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible (used by PageUp/PageDown) | ||||
|     ImGuiNavMoveFlags_AlsoScoreVisibleSet   = 1 << 5,   // Store alternate result in NavMoveResultLocalVisible that only comprise elements that are already fully visible (used by PageUp/PageDown) | ||||
|     ImGuiNavMoveFlags_ScrollToEdge          = 1 << 6, | ||||
|     ImGuiNavMoveFlags_Forwarded             = 1 << 7 | ||||
|     ImGuiNavMoveFlags_Forwarded             = 1 << 7, | ||||
|     ImGuiNavMoveFlags_DebugNoResult         = 1 << 8 | ||||
| }; | ||||
|  | ||||
| enum ImGuiNavLayer | ||||
| @@ -1686,34 +1689,40 @@ struct ImGuiContext | ||||
|     ImGuiID                 NavActivateId;                      // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() | ||||
|     ImGuiID                 NavActivateDownId;                  // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 | ||||
|     ImGuiID                 NavActivatePressedId;               // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 | ||||
|     ImGuiID                 NavInputId;                         // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 | ||||
|     ImGuiID                 NavActivateInputId;                 // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0; ImGuiActivateFlags_PreferInput will be set and NavActivateId will be 0. | ||||
|     ImGuiActivateFlags      NavActivateFlags; | ||||
|     ImGuiID                 NavJustTabbedId;                    // Just tabbed to this id. | ||||
|     ImGuiID                 NavJustMovedToId;                   // Just navigated to this id (result of a successfully MoveRequest). | ||||
|     ImGuiID                 NavJustMovedToFocusScopeId;         // Just navigated to this focus scope id (result of a successfully MoveRequest). | ||||
|     ImGuiKeyModFlags        NavJustMovedToKeyMods; | ||||
|     ImGuiID                 NavNextActivateId;                  // Set by ActivateItem(), queued until next frame. | ||||
|     ImGuiActivateFlags      NavNextActivateFlags; | ||||
|     ImGuiInputSource        NavInputSource;                     // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. | ||||
|     ImRect                  NavScoringRect;                     // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. | ||||
|     int                     NavScoringCount;                    // Metrics for debugging | ||||
|     ImGuiNavLayer           NavLayer;                           // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. | ||||
|     int                     NavIdTabCounter;                    // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing | ||||
|     bool                    NavIdIsAlive;                       // Nav widget has been seen this frame ~~ NavRectRel is valid | ||||
|     bool                    NavMousePosDirty;                   // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) | ||||
|     bool                    NavDisableHighlight;                // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) | ||||
|     bool                    NavDisableMouseHover;               // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. | ||||
|  | ||||
|     // Navigation: Init & Move Requests | ||||
|     bool                    NavAnyRequest;                      // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() | ||||
|     bool                    NavInitRequest;                     // Init request for appearing window to select first item | ||||
|     bool                    NavInitRequestFromMove; | ||||
|     ImGuiID                 NavInitResultId;                    // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) | ||||
|     ImRect                  NavInitResultRectRel;               // Init request result rectangle (relative to parent window) | ||||
|     bool                    NavMoveRequest;                     // Move request for this frame | ||||
|     bool                    NavMoveRequestForwardToNextFrame; | ||||
|     ImGuiNavMoveFlags       NavMoveRequestFlags; | ||||
|     ImGuiKeyModFlags        NavMoveRequestKeyMods; | ||||
|     ImGuiDir                NavMoveDir, NavMoveDirLast;         // Direction of the move request (left/right/up/down), direction of the previous move request | ||||
|     bool                    NavMoveSubmitted;                   // Move request submitted, will process result on next NewFrame() | ||||
|     bool                    NavMoveScoringItems;                // Move request submitted, still scoring incoming items | ||||
|     bool                    NavMoveForwardToNextFrame; | ||||
|     ImGuiNavMoveFlags       NavMoveFlags; | ||||
|     ImGuiKeyModFlags        NavMoveKeyMods; | ||||
|     ImGuiDir                NavMoveDir;                         // Direction of the move request (left/right/up/down) | ||||
|     ImGuiDir                NavMoveDirForDebug; | ||||
|     ImGuiDir                NavMoveClipDir;                     // FIXME-NAV: Describe the purpose of this better. Might want to rename? | ||||
|     ImRect                  NavScoringRect;                     // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. | ||||
|     int                     NavScoringDebugCount;               // Metrics for debugging | ||||
|     ImGuiNavItemData        NavMoveResultLocal;                 // Best move request candidate within NavWindow | ||||
|     ImGuiNavItemData        NavMoveResultLocalVisibleSet;       // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) | ||||
|     ImGuiNavItemData        NavMoveResultLocalVisible;          // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) | ||||
|     ImGuiNavItemData        NavMoveResultOther;                 // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) | ||||
|  | ||||
|     // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) | ||||
| @@ -1771,7 +1780,7 @@ struct ImGuiContext | ||||
|     ImVector<ImGuiShrinkWidthItem>  ShrinkWidthBuffer; | ||||
|  | ||||
|     // Widget state | ||||
|     ImVec2                  LastValidMousePos; | ||||
|     ImVec2                  MouseLastValidPos; | ||||
|     ImGuiInputTextState     InputTextState; | ||||
|     ImFont                  InputTextPasswordFont; | ||||
|     ImGuiID                 TempInputId;                        // Temporary text input when CTRL+clicking on a slider, etc. | ||||
| @@ -1905,12 +1914,11 @@ struct ImGuiContext | ||||
|         ViewportFrontMostStampCount = 0; | ||||
|  | ||||
|         NavWindow = NULL; | ||||
|         NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; | ||||
|         NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavActivateInputId = 0; | ||||
|         NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; | ||||
|         NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; | ||||
|         NavJustMovedToKeyMods = ImGuiKeyModFlags_None; | ||||
|         NavInputSource = ImGuiInputSource_None; | ||||
|         NavScoringRect = ImRect(); | ||||
|         NavScoringCount = 0; | ||||
|         NavLayer = ImGuiNavLayer_Main; | ||||
|         NavIdTabCounter = INT_MAX; | ||||
|         NavIdIsAlive = false; | ||||
| @@ -1921,11 +1929,13 @@ struct ImGuiContext | ||||
|         NavInitRequest = false; | ||||
|         NavInitRequestFromMove = false; | ||||
|         NavInitResultId = 0; | ||||
|         NavMoveRequest = false; | ||||
|         NavMoveRequestForwardToNextFrame = false; | ||||
|         NavMoveRequestFlags = ImGuiNavMoveFlags_None; | ||||
|         NavMoveRequestKeyMods = ImGuiKeyModFlags_None; | ||||
|         NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; | ||||
|         NavMoveSubmitted = false; | ||||
|         NavMoveScoringItems = false; | ||||
|         NavMoveForwardToNextFrame = false; | ||||
|         NavMoveFlags = ImGuiNavMoveFlags_None; | ||||
|         NavMoveKeyMods = ImGuiKeyModFlags_None; | ||||
|         NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None; | ||||
|         NavScoringDebugCount = 0; | ||||
|  | ||||
|         NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; | ||||
|         NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; | ||||
| @@ -1955,7 +1965,6 @@ struct ImGuiContext | ||||
|         CurrentTableStackIdx = -1; | ||||
|         CurrentTabBar = NULL; | ||||
|  | ||||
|         LastValidMousePos = ImVec2(0.0f, 0.0f); | ||||
|         TempInputId = 0; | ||||
|         ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; | ||||
|         ColorEditLastHue = ColorEditLastSat = 0.0f; | ||||
| @@ -2041,7 +2050,7 @@ struct IMGUI_API ImGuiWindowTempData | ||||
|     int                     CurrentTableIdx;        // Current table index (into g.Tables) | ||||
|     ImGuiLayoutType         LayoutType; | ||||
|     ImGuiLayoutType         ParentLayoutType;       // Layout type of parent window at the time of Begin() | ||||
|     int                     FocusCounterRegular;    // (Legacy Focus/Tabbing system) Sequential counter, start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign) | ||||
|     int                     FocusCounterRegular;    // (Legacy Focus/Tabbing system) Sequential counter, start at -1 and increase when ImGuiItemFlags_Inputable (FIXME-NAV: Needs redesign) | ||||
|     int                     FocusCounterTabStop;    // (Legacy Focus/Tabbing system) Same, but only count widgets which you can Tab through. | ||||
|  | ||||
|     // Local parameters stacks | ||||
| @@ -2627,9 +2636,9 @@ namespace ImGui | ||||
|     // Basic Helpers for widget code | ||||
|     IMGUI_API void          ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); | ||||
|     IMGUI_API void          ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); | ||||
|     IMGUI_API bool          ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemAddFlags flags = 0); | ||||
|     IMGUI_API bool          ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); | ||||
|     IMGUI_API bool          ItemHoverable(const ImRect& bb, ImGuiID id); | ||||
|     IMGUI_API void          ItemFocusable(ImGuiWindow* window, ImGuiID id); | ||||
|     IMGUI_API void          ItemInputable(ImGuiWindow* window, ImGuiID id); | ||||
|     IMGUI_API bool          IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); | ||||
|     IMGUI_API void          SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); | ||||
|     IMGUI_API ImVec2        CalcItemSize(ImVec2 size, float default_w, float default_h); | ||||
| @@ -2644,11 +2653,13 @@ namespace ImGui | ||||
|     IMGUI_API void          PopItemFlag(); | ||||
|  | ||||
| #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS | ||||
|     // Currently refactoring focus/nav/tabbing system | ||||
|     // If you have old/custom copy-and-pasted widgets that used FocusableItemRegister(): | ||||
|     //  (Old) IMGUI_VERSION_NUM  < 18209: using 'ItemAdd(....)'                              and 'bool focused = FocusableItemRegister(...)' | ||||
|     //  (New) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)'  and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' | ||||
|     //  (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)'  and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' | ||||
|     //  (New) IMGUI_VERSION_NUM >= 18411: using 'ItemAdd(..., ImGuiItemAddFlags_Inputable)'  and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' | ||||
|     // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() | ||||
|     inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id)  { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Focusable flag to ItemAdd() | ||||
|     inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id)  { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Inputable flag to ItemAdd() | ||||
|     inline void FocusableItemUnregister(ImGuiWindow* window)            { IM_ASSERT(0); IM_UNUSED(window); }                              // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem | ||||
| #endif | ||||
|  | ||||
| @@ -2683,7 +2694,9 @@ namespace ImGui | ||||
|  | ||||
|     // Gamepad/Keyboard Navigation | ||||
|     IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit); | ||||
|     IMGUI_API bool          NavMoveRequestButNoResultYet(); // Should be called ~NavMoveRequestIsActiveButNoResultYet() | ||||
|     IMGUI_API void          NavInitRequestApplyResult(); | ||||
|     IMGUI_API bool          NavMoveRequestButNoResultYet(); | ||||
|     IMGUI_API void          NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags); | ||||
|     IMGUI_API void          NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags); | ||||
|     IMGUI_API void          NavMoveRequestCancel(); | ||||
|     IMGUI_API void          NavMoveRequestApplyResult(); | ||||
|   | ||||
| @@ -1479,6 +1479,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) | ||||
|     table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b | ||||
|  | ||||
|     // Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered. | ||||
|     // FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section) | ||||
|     for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++) | ||||
|     { | ||||
|         int order_n = table->DisplayOrderToIndex[column_n]; | ||||
|   | ||||
| @@ -273,6 +273,7 @@ void ImGui::TextV(const char* fmt, va_list args) | ||||
|     if (window->SkipItems) | ||||
|         return; | ||||
|  | ||||
|     // FIXME-OPT: Handle the %s shortcut? | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); | ||||
|     TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); | ||||
| @@ -604,13 +605,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool | ||||
|         bool nav_activated_by_code = (g.NavActivateId == id); | ||||
|         bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); | ||||
|         if (nav_activated_by_code || nav_activated_by_inputs) | ||||
|             pressed = true; | ||||
|         if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) | ||||
|         { | ||||
|             // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. | ||||
|             g.NavActivateId = id; // This is so SetActiveId assign a Nav source | ||||
|             pressed = true; | ||||
|             SetActiveID(id, window); | ||||
|             if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus)) | ||||
|             g.ActiveIdSource = ImGuiInputSource_Nav; | ||||
|             if (!(flags & ImGuiButtonFlags_NoNavFocus)) | ||||
|                 SetFocusID(id, window); | ||||
|         } | ||||
|     } | ||||
| @@ -1587,7 +1587,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF | ||||
|     bool pressed = ButtonBehavior(bb, id, &hovered, &held); | ||||
|     const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id); | ||||
|     bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None); | ||||
|     if ((pressed || g.NavActivateId == id) && !popup_open) | ||||
|     if (pressed && !popup_open) | ||||
|     { | ||||
|         OpenPopupEx(popup_id, ImGuiPopupFlags_None); | ||||
|         popup_open = true; | ||||
| @@ -2395,7 +2395,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, | ||||
|  | ||||
|     const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; | ||||
|     ItemSize(total_bb, style.FramePadding.y); | ||||
|     if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemAddFlags_Focusable : 0)) | ||||
|     if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) | ||||
|         return false; | ||||
|  | ||||
|     // Default format string when passing NULL | ||||
| @@ -2412,21 +2412,23 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, | ||||
|         const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0; | ||||
|         const bool clicked = (hovered && g.IO.MouseClicked[0]); | ||||
|         const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); | ||||
|         if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) | ||||
|         if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavActivateInputId == id) | ||||
|         { | ||||
|             SetActiveID(id, window); | ||||
|             SetFocusID(id, window); | ||||
|             FocusWindow(window); | ||||
|             g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); | ||||
|             if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id)) | ||||
|                 temp_input_is_active = true; | ||||
|             if (temp_input_allowed) | ||||
|                 if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavActivateInputId == id) | ||||
|                     temp_input_is_active = true; | ||||
|         } | ||||
|  | ||||
|         // Experimental: simple click (without moving) turns Drag into an InputText | ||||
|         // FIXME: Currently polling ImGuiConfigFlags_IsTouchScreen, may either poll an hypothetical ImGuiBackendFlags_HasKeyboard and/or an explicit drag settings. | ||||
|         if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active) | ||||
|             if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) | ||||
|             { | ||||
|                 g.NavInputId = id; | ||||
|                 g.NavActivateId = g.NavActivateInputId = id; | ||||
|                 g.NavActivateFlags = ImGuiActivateFlags_PreferInput; | ||||
|                 temp_input_is_active = true; | ||||
|             } | ||||
|     } | ||||
| @@ -3011,7 +3013,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat | ||||
|  | ||||
|     const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; | ||||
|     ItemSize(total_bb, style.FramePadding.y); | ||||
|     if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemAddFlags_Focusable : 0)) | ||||
|     if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) | ||||
|         return false; | ||||
|  | ||||
|     // Default format string when passing NULL | ||||
| @@ -3027,13 +3029,13 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat | ||||
|     { | ||||
|         const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0; | ||||
|         const bool clicked = (hovered && g.IO.MouseClicked[0]); | ||||
|         if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) | ||||
|         if (focus_requested || clicked || g.NavActivateId == id || g.NavActivateInputId == id) | ||||
|         { | ||||
|             SetActiveID(id, window); | ||||
|             SetFocusID(id, window); | ||||
|             FocusWindow(window); | ||||
|             g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); | ||||
|             if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id)) | ||||
|             if (temp_input_allowed && (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavActivateInputId == id)) | ||||
|                 temp_input_is_active = true; | ||||
|         } | ||||
|     } | ||||
| @@ -3185,7 +3187,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d | ||||
|         format = PatchFormatStringFloatToInt(format); | ||||
|  | ||||
|     const bool hovered = ItemHoverable(frame_bb, id); | ||||
|     if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) | ||||
|     if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavActivateInputId == id) | ||||
|     { | ||||
|         SetActiveID(id, window); | ||||
|         SetFocusID(id, window); | ||||
| @@ -3449,7 +3451,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data | ||||
|         style.FramePadding.x = style.FramePadding.y; | ||||
|         ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; | ||||
|         if (flags & ImGuiInputTextFlags_ReadOnly) | ||||
|             BeginDisabled(true); | ||||
|             BeginDisabled(); | ||||
|         SameLine(0, style.ItemInnerSpacing.x); | ||||
|         if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) | ||||
|         { | ||||
| @@ -3981,7 +3983,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|     { | ||||
|         ImVec2 backup_pos = window->DC.CursorPos; | ||||
|         ItemSize(total_bb, style.FramePadding.y); | ||||
|         if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable)) | ||||
|         if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) | ||||
|         { | ||||
|             EndGroup(); | ||||
|             return false; | ||||
| @@ -4012,7 +4014,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|         // Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd) | ||||
|         ItemSize(total_bb, style.FramePadding.y); | ||||
|         if (!(flags & ImGuiInputTextFlags_MergedItem)) | ||||
|             if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable)) | ||||
|             if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) | ||||
|                 return false; | ||||
|         item_status_flags = g.LastItemData.StatusFlags; | ||||
|     } | ||||
| @@ -4027,7 +4029,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|     const bool focus_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; | ||||
|  | ||||
|     const bool user_clicked = hovered && io.MouseClicked[0]; | ||||
|     const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard)); | ||||
|     const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavActivateInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard)); | ||||
|     const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); | ||||
|     const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); | ||||
|  | ||||
| @@ -4254,6 +4256,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|         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_readonly && is_undoable; | ||||
|  | ||||
|         // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. | ||||
|         const bool is_validate = IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter) || IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed) || IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); | ||||
|         const bool is_cancel   = IsKeyPressedMap(ImGuiKey_Escape) || IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed); | ||||
|  | ||||
|         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))                  { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } | ||||
|         else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline)     { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } | ||||
| @@ -4274,7 +4280,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|             } | ||||
|             state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); | ||||
|         } | ||||
|         else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter)) | ||||
|         else if (is_validate) | ||||
|         { | ||||
|             bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; | ||||
|             if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) | ||||
| @@ -4288,7 +4294,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ | ||||
|                     state->OnKeyPressed((int)c); | ||||
|             } | ||||
|         } | ||||
|         else if (IsKeyPressedMap(ImGuiKey_Escape)) | ||||
|         else if (is_cancel) | ||||
|         { | ||||
|             clear_active_id = cancel_edit = true; | ||||
|         } | ||||
| @@ -6153,20 +6159,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl | ||||
|         window->ClipRect.Max.x = window->ParentWorkRect.Max.x; | ||||
|     } | ||||
|  | ||||
|     bool item_add; | ||||
|     const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; | ||||
|     if (disabled_item) | ||||
|     { | ||||
|         ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; | ||||
|         g.CurrentItemFlags |= ImGuiItemFlags_Disabled; | ||||
|         item_add = ItemAdd(bb, id); | ||||
|         g.CurrentItemFlags = backup_item_flags; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         item_add = ItemAdd(bb, id); | ||||
|     } | ||||
|  | ||||
|     const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None); | ||||
|     if (span_all_columns) | ||||
|     { | ||||
|         window->ClipRect.Min.x = backup_clip_rect_min_x; | ||||
| @@ -6178,7 +6172,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl | ||||
|  | ||||
|     const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; | ||||
|     if (disabled_item && !disabled_global) // Only testing this as an optimization | ||||
|         BeginDisabled(true); | ||||
|         BeginDisabled(); | ||||
|  | ||||
|     // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, | ||||
|     // which would be advantageous since most selectable are not selected. | ||||
| @@ -6215,7 +6209,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl | ||||
|     { | ||||
|         if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) | ||||
|         { | ||||
|             SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos)); | ||||
|             SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos)); // (bb == NavRect) | ||||
|             g.NavDisableHighlight = true; | ||||
|         } | ||||
|     } | ||||
| @@ -6480,7 +6474,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get | ||||
|         float v0 = values_getter(data, (0 + values_offset) % values_count); | ||||
|         float t0 = 0.0f; | ||||
|         ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) );                       // Point in the normalized space of our target rectangle | ||||
|         float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f);   // Where does the zero line stands | ||||
|         float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f);   // Where does the zero line stands | ||||
|  | ||||
|         const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); | ||||
|         const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); | ||||
| @@ -6696,10 +6690,11 @@ void ImGui::EndMenuBar() | ||||
|     // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. | ||||
|     if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|     { | ||||
|         // Try to find out if the request is for one of our child menu | ||||
|         ImGuiWindow* nav_earliest_child = g.NavWindow; | ||||
|         while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) | ||||
|             nav_earliest_child = nav_earliest_child->ParentWindow; | ||||
|         if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0) | ||||
|         if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) | ||||
|         { | ||||
|             // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. | ||||
|             // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering) | ||||
| @@ -6709,7 +6704,7 @@ void ImGui::EndMenuBar() | ||||
|             SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); | ||||
|             g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. | ||||
|             g.NavDisableMouseHover = g.NavMousePosDirty = true; | ||||
|             NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveRequestFlags); // Repeat | ||||
|             NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags); // Repeat | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -6894,37 +6889,29 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) | ||||
|         // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu | ||||
|         // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. | ||||
|         bool moving_toward_other_child_menu = false; | ||||
|  | ||||
|         ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL; | ||||
|         if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar)) | ||||
|         { | ||||
|             // FIXME-DPI: Values should be derived from a master "scale" factor. | ||||
|             float ref_unit = g.FontSize; // FIXME-DPI | ||||
|             ImRect next_window_rect = child_menu_window->Rect(); | ||||
|             ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; | ||||
|             ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta); | ||||
|             ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); | ||||
|             ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); | ||||
|             float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f);    // add a bit of extra slack. | ||||
|             ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues | ||||
|             tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f);                // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? | ||||
|             tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); | ||||
|             float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f);   // add a bit of extra slack. | ||||
|             ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f;                     // to avoid numerical issues (FIXME: ??) | ||||
|             tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f);                           // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? | ||||
|             tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f); | ||||
|             moving_toward_other_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); | ||||
|             //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] | ||||
|             //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_other_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] | ||||
|         } | ||||
|  | ||||
|         // FIXME: Hovering a disabled BeginMenu or MenuItem won't close us | ||||
|         if (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_toward_other_child_menu) | ||||
|             want_close = true; | ||||
|  | ||||
|         if (!menu_is_open && hovered && pressed) // Click to open | ||||
|         // Open | ||||
|         if (!menu_is_open && pressed) // Click/activate to open | ||||
|             want_open = true; | ||||
|         else if (!menu_is_open && hovered && !moving_toward_other_child_menu) // Hover to open | ||||
|             want_open = true; | ||||
|  | ||||
|         if (g.NavActivateId == id) | ||||
|         { | ||||
|             want_close = menu_is_open; | ||||
|             want_open = !menu_is_open; | ||||
|         } | ||||
|         if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open | ||||
|         { | ||||
|             want_open = true; | ||||
| @@ -7019,7 +7006,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut | ||||
|     bool pressed; | ||||
|     PushID(label); | ||||
|     if (!enabled) | ||||
|         BeginDisabled(true); | ||||
|         BeginDisabled(); | ||||
|     const ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover; | ||||
|     const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | ||||
|     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user