@ -2962,254 +2962,6 @@ static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item
}
}
}
}
static void ImGui : : NavUpdate ( )
{
ImGuiContext & g = * GImGui ;
g . IO . WantSetMousePos = false ;
#if 0
if ( g . NavScoringCount > 0 ) printf ( " [%05d] 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
// Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard)
bool nav_keyboard_active = ( g . IO . ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard ) ! = 0 ;
bool nav_gamepad_active = ( g . IO . ConfigFlags & ImGuiConfigFlags_NavEnableGamepad ) ! = 0 & & ( g . IO . BackendFlags & ImGuiBackendFlags_HasGamepad ) ! = 0 ;
if ( nav_gamepad_active )
if ( g . IO . NavInputs [ ImGuiNavInput_Activate ] > 0.0f | | g . IO . NavInputs [ ImGuiNavInput_Input ] > 0.0f | | g . IO . NavInputs [ ImGuiNavInput_Cancel ] > 0.0f | | g . IO . NavInputs [ ImGuiNavInput_Menu ] > 0.0f )
g . NavInputSource = ImGuiInputSource_NavGamepad ;
// Update Keyboard->Nav inputs mapping
if ( nav_keyboard_active )
{
# define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
NAV_MAP_KEY ( ImGuiKey_Space , ImGuiNavInput_Activate ) ;
NAV_MAP_KEY ( ImGuiKey_Enter , ImGuiNavInput_Input ) ;
NAV_MAP_KEY ( ImGuiKey_Escape , ImGuiNavInput_Cancel ) ;
NAV_MAP_KEY ( ImGuiKey_LeftArrow , ImGuiNavInput_KeyLeft_ ) ;
NAV_MAP_KEY ( ImGuiKey_RightArrow , ImGuiNavInput_KeyRight_ ) ;
NAV_MAP_KEY ( ImGuiKey_UpArrow , ImGuiNavInput_KeyUp_ ) ;
NAV_MAP_KEY ( ImGuiKey_DownArrow , ImGuiNavInput_KeyDown_ ) ;
if ( g . IO . KeyCtrl ) g . IO . NavInputs [ ImGuiNavInput_TweakSlow ] = 1.0f ;
if ( g . IO . KeyShift ) g . IO . NavInputs [ ImGuiNavInput_TweakFast ] = 1.0f ;
if ( g . IO . KeyAlt ) g . IO . NavInputs [ ImGuiNavInput_KeyMenu_ ] = 1.0f ;
# undef NAV_MAP_KEY
}
memcpy ( g . IO . NavInputsDownDurationPrev , g . IO . NavInputsDownDuration , sizeof ( g . IO . NavInputsDownDuration ) ) ;
for ( int i = 0 ; i < IM_ARRAYSIZE ( g . IO . NavInputs ) ; i + + )
g . IO . NavInputsDownDuration [ i ] = ( g . IO . NavInputs [ i ] > 0.0f ) ? ( g . IO . NavInputsDownDuration [ i ] < 0.0f ? 0.0f : g . IO . NavInputsDownDuration [ i ] + g . IO . DeltaTime ) : - 1.0f ;
// Process navigation init request (select first/default focus)
if ( g . NavInitResultId ! = 0 & & ( ! g . NavDisableHighlight | | g . NavInitRequestFromMove ) )
{
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
IM_ASSERT ( g . NavWindow ) ;
if ( g . NavInitRequestFromMove )
SetNavIDWithRectRel ( g . NavInitResultId , g . NavLayer , g . NavInitResultRectRel ) ;
else
SetNavID ( g . NavInitResultId , g . NavLayer ) ;
g . NavWindow - > NavRectRel [ g . NavLayer ] = g . NavInitResultRectRel ;
}
g . NavInitRequest = false ;
g . NavInitRequestFromMove = false ;
g . NavInitResultId = 0 ;
g . NavJustMovedToId = 0 ;
// Process navigation move request
if ( g . NavMoveRequest & & ( g . NavMoveResultLocal . ID ! = 0 | | g . NavMoveResultOther . ID ! = 0 ) )
NavUpdateMoveResult ( ) ;
// When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
if ( g . NavMoveRequestForward = = ImGuiNavForward_ForwardActive )
{
IM_ASSERT ( g . NavMoveRequest ) ;
if ( g . NavMoveResultLocal . ID = = 0 & & g . NavMoveResultOther . ID = = 0 )
g . NavDisableHighlight = false ;
g . NavMoveRequestForward = ImGuiNavForward_None ;
}
// Apply application mouse position movement, after we had a chance to process move request result.
if ( g . NavMousePosDirty & & g . NavIdIsAlive )
{
// Set mouse position given our knowledge of the navigated item position from last frame
if ( ( g . IO . ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos ) & & ( g . IO . BackendFlags & ImGuiBackendFlags_HasSetMousePos ) )
{
if ( ! g . NavDisableHighlight & & g . NavDisableMouseHover & & g . NavWindow )
{
g . IO . MousePos = g . IO . MousePosPrev = NavCalcPreferredRefPos ( ) ;
g . IO . WantSetMousePos = true ;
}
}
g . NavMousePosDirty = false ;
}
g . NavIdIsAlive = false ;
g . NavJustTabbedId = 0 ;
IM_ASSERT ( g . NavLayer = = 0 | | g . NavLayer = = 1 ) ;
// Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0
if ( g . NavWindow )
NavSaveLastChildNavWindow ( g . NavWindow ) ;
if ( g . NavWindow & & g . NavWindow - > NavLastChildNavWindow ! = NULL & & g . NavLayer = = 0 )
g . NavWindow - > NavLastChildNavWindow = NULL ;
// Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
NavUpdateWindowing ( ) ;
// Set output flags for user application
g . IO . NavActive = ( nav_keyboard_active | | nav_gamepad_active ) & & g . NavWindow & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) ;
g . IO . NavVisible = ( g . IO . NavActive & & g . NavId ! = 0 & & ! g . NavDisableHighlight ) | | ( g . NavWindowingTarget ! = NULL ) | | g . NavInitRequest ;
// Process NavCancel input (to close a popup, get back to parent, clear focus)
if ( IsNavInputPressed ( ImGuiNavInput_Cancel , ImGuiInputReadMode_Pressed ) )
{
if ( g . ActiveId ! = 0 )
{
ClearActiveID ( ) ;
}
else if ( g . NavWindow & & ( g . NavWindow - > Flags & ImGuiWindowFlags_ChildWindow ) & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_Popup ) & & g . NavWindow - > ParentWindow )
{
// Exit child window
ImGuiWindow * child_window = g . NavWindow ;
ImGuiWindow * parent_window = g . NavWindow - > ParentWindow ;
IM_ASSERT ( child_window - > ChildId ! = 0 ) ;
FocusWindow ( parent_window ) ;
SetNavID ( child_window - > ChildId , 0 ) ;
g . NavIdIsAlive = false ;
if ( g . NavDisableMouseHover )
g . NavMousePosDirty = true ;
}
else if ( g . OpenPopupStack . Size > 0 )
{
// Close open popup/menu
if ( ! ( g . OpenPopupStack . back ( ) . Window - > Flags & ImGuiWindowFlags_Modal ) )
ClosePopupToLevel ( g . OpenPopupStack . Size - 1 ) ;
}
else if ( g . NavLayer ! = 0 )
{
// Leave the "menu" layer
NavRestoreLayer ( 0 ) ;
}
else
{
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
if ( g . NavWindow & & ( ( g . NavWindow - > Flags & ImGuiWindowFlags_Popup ) | | ! ( g . NavWindow - > Flags & ImGuiWindowFlags_ChildWindow ) ) )
g . NavWindow - > NavLastIds [ 0 ] = 0 ;
g . NavId = 0 ;
}
}
// Process manual activation request
g . NavActivateId = g . NavActivateDownId = g . NavActivatePressedId = g . NavInputId = 0 ;
if ( g . NavId ! = 0 & & ! g . NavDisableHighlight & & ! g . NavWindowingTarget & & g . NavWindow & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) )
{
bool activate_down = IsNavInputDown ( ImGuiNavInput_Activate ) ;
bool activate_pressed = activate_down & & IsNavInputPressed ( ImGuiNavInput_Activate , ImGuiInputReadMode_Pressed ) ;
if ( g . ActiveId = = 0 & & activate_pressed )
g . NavActivateId = g . NavId ;
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 ) & & IsNavInputPressed ( ImGuiNavInput_Input , ImGuiInputReadMode_Pressed ) )
g . NavInputId = g . NavId ;
}
if ( g . NavWindow & & ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) )
g . NavDisableHighlight = true ;
if ( g . NavActivateId ! = 0 )
IM_ASSERT ( g . NavActivateDownId = = g . NavActivateId ) ;
g . NavMoveRequest = false ;
// Process programmatic activation request
if ( g . NavNextActivateId ! = 0 )
g . NavActivateId = g . NavActivateDownId = g . NavActivatePressedId = g . NavInputId = g . NavNextActivateId ;
g . NavNextActivateId = 0 ;
// Initiate directional inputs request
const int allowed_dir_flags = ( g . ActiveId = = 0 ) ? ~ 0 : g . ActiveIdAllowNavDirFlags ;
if ( g . NavMoveRequestForward = = ImGuiNavForward_None )
{
g . NavMoveDir = ImGuiDir_None ;
g . NavMoveRequestFlags = 0 ;
if ( g . NavWindow & & ! g . NavWindowingTarget & & allowed_dir_flags & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) )
{
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Left ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadLeft , ImGuiNavInput_KeyLeft_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Left ;
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Right ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadRight , ImGuiNavInput_KeyRight_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Right ;
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Up ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadUp , ImGuiNavInput_KeyUp_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Up ;
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Down ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadDown , ImGuiNavInput_KeyDown_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Down ;
}
g . NavMoveClipDir = g . NavMoveDir ;
}
else
{
// 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 g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
IM_ASSERT ( g . NavMoveDir ! = ImGuiDir_None & & g . NavMoveClipDir ! = ImGuiDir_None ) ;
IM_ASSERT ( g . NavMoveRequestForward = = ImGuiNavForward_ForwardQueued ) ;
g . NavMoveRequestForward = ImGuiNavForward_ForwardActive ;
}
// Update PageUp/PageDown scroll
float nav_scoring_rect_offset_y = 0.0f ;
if ( nav_keyboard_active )
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown ( allowed_dir_flags ) ;
// If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
if ( g . NavMoveDir ! = ImGuiDir_None )
{
g . NavMoveRequest = true ;
g . NavMoveDirLast = g . NavMoveDir ;
}
if ( g . NavMoveRequest & & g . NavId = = 0 )
{
g . NavInitRequest = g . NavInitRequestFromMove = true ;
g . NavInitResultId = 0 ;
g . NavDisableHighlight = false ;
}
NavUpdateAnyRequestFlag ( ) ;
// Scrolling
if ( g . NavWindow & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) & & ! g . NavWindowingTarget )
{
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
ImGuiWindow * window = g . NavWindow ;
const float scroll_speed = ImFloor ( window - > CalcFontSize ( ) * 100 * g . IO . DeltaTime + 0.5f ) ; // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
if ( window - > DC . NavLayerActiveMask = = 0x00 & & window - > DC . NavHasScroll & & g . NavMoveRequest )
{
if ( g . NavMoveDir = = ImGuiDir_Left | | g . NavMoveDir = = ImGuiDir_Right )
SetWindowScrollX ( window , ImFloor ( window - > Scroll . x + ( ( g . NavMoveDir = = ImGuiDir_Left ) ? - 1.0f : + 1.0f ) * scroll_speed ) ) ;
if ( g . NavMoveDir = = ImGuiDir_Up | | g . NavMoveDir = = ImGuiDir_Down )
SetWindowScrollY ( window , ImFloor ( window - > Scroll . y + ( ( g . NavMoveDir = = ImGuiDir_Up ) ? - 1.0f : + 1.0f ) * scroll_speed ) ) ;
}
// *Normal* Manual scroll with NavScrollXXX keys
// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
ImVec2 scroll_dir = GetNavInputAmount2d ( ImGuiNavDirSourceFlags_PadLStick , ImGuiInputReadMode_Down , 1.0f / 10.0f , 10.0f ) ;
if ( scroll_dir . x ! = 0.0f & & window - > ScrollbarX )
{
SetWindowScrollX ( window , ImFloor ( window - > Scroll . x + scroll_dir . x * scroll_speed ) ) ;
g . NavMoveFromClampedRefRect = true ;
}
if ( scroll_dir . y ! = 0.0f )
{
SetWindowScrollY ( window , ImFloor ( window - > Scroll . y + scroll_dir . y * scroll_speed ) ) ;
g . NavMoveFromClampedRefRect = true ;
}
}
// Reset search results
g . NavMoveResultLocal . Clear ( ) ;
g . NavMoveResultLocalVisibleSet . Clear ( ) ;
g . NavMoveResultOther . Clear ( ) ;
// When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
if ( g . NavMoveRequest & & g . NavMoveFromClampedRefRect & & g . NavLayer = = 0 )
{
ImGuiWindow * window = g . NavWindow ;
ImRect window_rect_rel ( window - > InnerMainRect . Min - window - > Pos - ImVec2 ( 1 , 1 ) , window - > InnerMainRect . Max - window - > Pos + ImVec2 ( 1 , 1 ) ) ;
if ( ! window_rect_rel . Contains ( window - > NavRectRel [ g . NavLayer ] ) )
{
float pad = window - > CalcFontSize ( ) * 0.5f ;
window_rect_rel . Expand ( ImVec2 ( - ImMin ( window_rect_rel . GetWidth ( ) , pad ) , - ImMin ( window_rect_rel . GetHeight ( ) , pad ) ) ) ; // Terrible approximation for the intent of starting navigation from first fully visible item
window - > NavRectRel [ g . NavLayer ] . ClipWith ( window_rect_rel ) ;
g . NavId = 0 ;
}
g . NavMoveFromClampedRefRect = false ;
}
// 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)
ImRect nav_rect_rel = ( g . NavWindow & & ! g . NavWindow - > NavRectRel [ g . NavLayer ] . IsInverted ( ) ) ? g . NavWindow - > NavRectRel [ g . NavLayer ] : ImRect ( 0 , 0 , 0 , 0 ) ;
g . NavScoringRectScreen = g . NavWindow ? ImRect ( g . NavWindow - > Pos + nav_rect_rel . Min , g . NavWindow - > Pos + nav_rect_rel . Max ) : GetViewportRect ( ) ;
g . NavScoringRectScreen . TranslateY ( nav_scoring_rect_offset_y ) ;
g . NavScoringRectScreen . Min . x = ImMin ( g . NavScoringRectScreen . Min . x + 1.0f , g . NavScoringRectScreen . Max . x ) ;
g . NavScoringRectScreen . Max . x = g . NavScoringRectScreen . Min . x ;
IM_ASSERT ( ! g . NavScoringRectScreen . IsInverted ( ) ) ; // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
//g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
g . NavScoringCount = 0 ;
# if IMGUI_DEBUG_NAV_RECTS
if ( g . NavWindow ) { for ( int layer = 0 ; layer < 2 ; layer + + ) GetOverlayDrawList ( ) - > AddRect ( g . NavWindow - > Pos + g . NavWindow - > NavRectRel [ layer ] . Min , g . NavWindow - > Pos + g . NavWindow - > NavRectRel [ layer ] . Max , IM_COL32 ( 255 , 200 , 0 , 255 ) ) ; } // [DEBUG]
if ( g . NavWindow ) { ImU32 col = ( g . NavWindow - > HiddenFrames = = 0 ) ? IM_COL32 ( 255 , 0 , 255 , 255 ) : IM_COL32 ( 255 , 0 , 0 , 255 ) ; ImVec2 p = NavCalcPreferredRefPos ( ) ; char buf [ 32 ] ; ImFormatString ( buf , 32 , " %d " , g . NavLayer ) ; g . OverlayDrawList . AddCircleFilled ( p , 3.0f , col ) ; g . OverlayDrawList . AddText ( NULL , 13.0f , p + ImVec2 ( 8 , - 4 ) , col , buf ) ; }
# endif
}
void ImGui : : StartMouseMovingWindow ( ImGuiWindow * window )
void ImGui : : StartMouseMovingWindow ( ImGuiWindow * window )
{
{
// Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
// Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
@ -7764,7 +7516,253 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov
}
}
}
}
//
static void ImGui : : NavUpdate ( )
{
ImGuiContext & g = * GImGui ;
g . IO . WantSetMousePos = false ;
#if 0
if ( g . NavScoringCount > 0 ) printf ( " [%05d] 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
// Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard)
bool nav_keyboard_active = ( g . IO . ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard ) ! = 0 ;
bool nav_gamepad_active = ( g . IO . ConfigFlags & ImGuiConfigFlags_NavEnableGamepad ) ! = 0 & & ( g . IO . BackendFlags & ImGuiBackendFlags_HasGamepad ) ! = 0 ;
if ( nav_gamepad_active )
if ( g . IO . NavInputs [ ImGuiNavInput_Activate ] > 0.0f | | g . IO . NavInputs [ ImGuiNavInput_Input ] > 0.0f | | g . IO . NavInputs [ ImGuiNavInput_Cancel ] > 0.0f | | g . IO . NavInputs [ ImGuiNavInput_Menu ] > 0.0f )
g . NavInputSource = ImGuiInputSource_NavGamepad ;
// Update Keyboard->Nav inputs mapping
if ( nav_keyboard_active )
{
# define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
NAV_MAP_KEY ( ImGuiKey_Space , ImGuiNavInput_Activate ) ;
NAV_MAP_KEY ( ImGuiKey_Enter , ImGuiNavInput_Input ) ;
NAV_MAP_KEY ( ImGuiKey_Escape , ImGuiNavInput_Cancel ) ;
NAV_MAP_KEY ( ImGuiKey_LeftArrow , ImGuiNavInput_KeyLeft_ ) ;
NAV_MAP_KEY ( ImGuiKey_RightArrow , ImGuiNavInput_KeyRight_ ) ;
NAV_MAP_KEY ( ImGuiKey_UpArrow , ImGuiNavInput_KeyUp_ ) ;
NAV_MAP_KEY ( ImGuiKey_DownArrow , ImGuiNavInput_KeyDown_ ) ;
if ( g . IO . KeyCtrl ) g . IO . NavInputs [ ImGuiNavInput_TweakSlow ] = 1.0f ;
if ( g . IO . KeyShift ) g . IO . NavInputs [ ImGuiNavInput_TweakFast ] = 1.0f ;
if ( g . IO . KeyAlt ) g . IO . NavInputs [ ImGuiNavInput_KeyMenu_ ] = 1.0f ;
# undef NAV_MAP_KEY
}
memcpy ( g . IO . NavInputsDownDurationPrev , g . IO . NavInputsDownDuration , sizeof ( g . IO . NavInputsDownDuration ) ) ;
for ( int i = 0 ; i < IM_ARRAYSIZE ( g . IO . NavInputs ) ; i + + )
g . IO . NavInputsDownDuration [ i ] = ( g . IO . NavInputs [ i ] > 0.0f ) ? ( g . IO . NavInputsDownDuration [ i ] < 0.0f ? 0.0f : g . IO . NavInputsDownDuration [ i ] + g . IO . DeltaTime ) : - 1.0f ;
// Process navigation init request (select first/default focus)
if ( g . NavInitResultId ! = 0 & & ( ! g . NavDisableHighlight | | g . NavInitRequestFromMove ) )
{
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
IM_ASSERT ( g . NavWindow ) ;
if ( g . NavInitRequestFromMove )
SetNavIDWithRectRel ( g . NavInitResultId , g . NavLayer , g . NavInitResultRectRel ) ;
else
SetNavID ( g . NavInitResultId , g . NavLayer ) ;
g . NavWindow - > NavRectRel [ g . NavLayer ] = g . NavInitResultRectRel ;
}
g . NavInitRequest = false ;
g . NavInitRequestFromMove = false ;
g . NavInitResultId = 0 ;
g . NavJustMovedToId = 0 ;
// Process navigation move request
if ( g . NavMoveRequest & & ( g . NavMoveResultLocal . ID ! = 0 | | g . NavMoveResultOther . ID ! = 0 ) )
NavUpdateMoveResult ( ) ;
// When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
if ( g . NavMoveRequestForward = = ImGuiNavForward_ForwardActive )
{
IM_ASSERT ( g . NavMoveRequest ) ;
if ( g . NavMoveResultLocal . ID = = 0 & & g . NavMoveResultOther . ID = = 0 )
g . NavDisableHighlight = false ;
g . NavMoveRequestForward = ImGuiNavForward_None ;
}
// Apply application mouse position movement, after we had a chance to process move request result.
if ( g . NavMousePosDirty & & g . NavIdIsAlive )
{
// Set mouse position given our knowledge of the navigated item position from last frame
if ( ( g . IO . ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos ) & & ( g . IO . BackendFlags & ImGuiBackendFlags_HasSetMousePos ) )
{
if ( ! g . NavDisableHighlight & & g . NavDisableMouseHover & & g . NavWindow )
{
g . IO . MousePos = g . IO . MousePosPrev = NavCalcPreferredRefPos ( ) ;
g . IO . WantSetMousePos = true ;
}
}
g . NavMousePosDirty = false ;
}
g . NavIdIsAlive = false ;
g . NavJustTabbedId = 0 ;
IM_ASSERT ( g . NavLayer = = 0 | | g . NavLayer = = 1 ) ;
// Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0
if ( g . NavWindow )
NavSaveLastChildNavWindow ( g . NavWindow ) ;
if ( g . NavWindow & & g . NavWindow - > NavLastChildNavWindow ! = NULL & & g . NavLayer = = 0 )
g . NavWindow - > NavLastChildNavWindow = NULL ;
// Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
NavUpdateWindowing ( ) ;
// Set output flags for user application
g . IO . NavActive = ( nav_keyboard_active | | nav_gamepad_active ) & & g . NavWindow & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) ;
g . IO . NavVisible = ( g . IO . NavActive & & g . NavId ! = 0 & & ! g . NavDisableHighlight ) | | ( g . NavWindowingTarget ! = NULL ) | | g . NavInitRequest ;
// Process NavCancel input (to close a popup, get back to parent, clear focus)
if ( IsNavInputPressed ( ImGuiNavInput_Cancel , ImGuiInputReadMode_Pressed ) )
{
if ( g . ActiveId ! = 0 )
{
ClearActiveID ( ) ;
}
else if ( g . NavWindow & & ( g . NavWindow - > Flags & ImGuiWindowFlags_ChildWindow ) & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_Popup ) & & g . NavWindow - > ParentWindow )
{
// Exit child window
ImGuiWindow * child_window = g . NavWindow ;
ImGuiWindow * parent_window = g . NavWindow - > ParentWindow ;
IM_ASSERT ( child_window - > ChildId ! = 0 ) ;
FocusWindow ( parent_window ) ;
SetNavID ( child_window - > ChildId , 0 ) ;
g . NavIdIsAlive = false ;
if ( g . NavDisableMouseHover )
g . NavMousePosDirty = true ;
}
else if ( g . OpenPopupStack . Size > 0 )
{
// Close open popup/menu
if ( ! ( g . OpenPopupStack . back ( ) . Window - > Flags & ImGuiWindowFlags_Modal ) )
ClosePopupToLevel ( g . OpenPopupStack . Size - 1 ) ;
}
else if ( g . NavLayer ! = 0 )
{
// Leave the "menu" layer
NavRestoreLayer ( 0 ) ;
}
else
{
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
if ( g . NavWindow & & ( ( g . NavWindow - > Flags & ImGuiWindowFlags_Popup ) | | ! ( g . NavWindow - > Flags & ImGuiWindowFlags_ChildWindow ) ) )
g . NavWindow - > NavLastIds [ 0 ] = 0 ;
g . NavId = 0 ;
}
}
// Process manual activation request
g . NavActivateId = g . NavActivateDownId = g . NavActivatePressedId = g . NavInputId = 0 ;
if ( g . NavId ! = 0 & & ! g . NavDisableHighlight & & ! g . NavWindowingTarget & & g . NavWindow & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) )
{
bool activate_down = IsNavInputDown ( ImGuiNavInput_Activate ) ;
bool activate_pressed = activate_down & & IsNavInputPressed ( ImGuiNavInput_Activate , ImGuiInputReadMode_Pressed ) ;
if ( g . ActiveId = = 0 & & activate_pressed )
g . NavActivateId = g . NavId ;
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 ) & & IsNavInputPressed ( ImGuiNavInput_Input , ImGuiInputReadMode_Pressed ) )
g . NavInputId = g . NavId ;
}
if ( g . NavWindow & & ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) )
g . NavDisableHighlight = true ;
if ( g . NavActivateId ! = 0 )
IM_ASSERT ( g . NavActivateDownId = = g . NavActivateId ) ;
g . NavMoveRequest = false ;
// Process programmatic activation request
if ( g . NavNextActivateId ! = 0 )
g . NavActivateId = g . NavActivateDownId = g . NavActivatePressedId = g . NavInputId = g . NavNextActivateId ;
g . NavNextActivateId = 0 ;
// Initiate directional inputs request
const int allowed_dir_flags = ( g . ActiveId = = 0 ) ? ~ 0 : g . ActiveIdAllowNavDirFlags ;
if ( g . NavMoveRequestForward = = ImGuiNavForward_None )
{
g . NavMoveDir = ImGuiDir_None ;
g . NavMoveRequestFlags = 0 ;
if ( g . NavWindow & & ! g . NavWindowingTarget & & allowed_dir_flags & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) )
{
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Left ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadLeft , ImGuiNavInput_KeyLeft_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Left ;
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Right ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadRight , ImGuiNavInput_KeyRight_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Right ;
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Up ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadUp , ImGuiNavInput_KeyUp_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Up ;
if ( ( allowed_dir_flags & ( 1 < < ImGuiDir_Down ) ) & & IsNavInputPressedAnyOfTwo ( ImGuiNavInput_DpadDown , ImGuiNavInput_KeyDown_ , ImGuiInputReadMode_Repeat ) ) g . NavMoveDir = ImGuiDir_Down ;
}
g . NavMoveClipDir = g . NavMoveDir ;
}
else
{
// 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 g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
IM_ASSERT ( g . NavMoveDir ! = ImGuiDir_None & & g . NavMoveClipDir ! = ImGuiDir_None ) ;
IM_ASSERT ( g . NavMoveRequestForward = = ImGuiNavForward_ForwardQueued ) ;
g . NavMoveRequestForward = ImGuiNavForward_ForwardActive ;
}
// Update PageUp/PageDown scroll
float nav_scoring_rect_offset_y = 0.0f ;
if ( nav_keyboard_active )
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown ( allowed_dir_flags ) ;
// If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
if ( g . NavMoveDir ! = ImGuiDir_None )
{
g . NavMoveRequest = true ;
g . NavMoveDirLast = g . NavMoveDir ;
}
if ( g . NavMoveRequest & & g . NavId = = 0 )
{
g . NavInitRequest = g . NavInitRequestFromMove = true ;
g . NavInitResultId = 0 ;
g . NavDisableHighlight = false ;
}
NavUpdateAnyRequestFlag ( ) ;
// Scrolling
if ( g . NavWindow & & ! ( g . NavWindow - > Flags & ImGuiWindowFlags_NoNavInputs ) & & ! g . NavWindowingTarget )
{
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
ImGuiWindow * window = g . NavWindow ;
const float scroll_speed = ImFloor ( window - > CalcFontSize ( ) * 100 * g . IO . DeltaTime + 0.5f ) ; // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
if ( window - > DC . NavLayerActiveMask = = 0x00 & & window - > DC . NavHasScroll & & g . NavMoveRequest )
{
if ( g . NavMoveDir = = ImGuiDir_Left | | g . NavMoveDir = = ImGuiDir_Right )
SetWindowScrollX ( window , ImFloor ( window - > Scroll . x + ( ( g . NavMoveDir = = ImGuiDir_Left ) ? - 1.0f : + 1.0f ) * scroll_speed ) ) ;
if ( g . NavMoveDir = = ImGuiDir_Up | | g . NavMoveDir = = ImGuiDir_Down )
SetWindowScrollY ( window , ImFloor ( window - > Scroll . y + ( ( g . NavMoveDir = = ImGuiDir_Up ) ? - 1.0f : + 1.0f ) * scroll_speed ) ) ;
}
// *Normal* Manual scroll with NavScrollXXX keys
// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
ImVec2 scroll_dir = GetNavInputAmount2d ( ImGuiNavDirSourceFlags_PadLStick , ImGuiInputReadMode_Down , 1.0f / 10.0f , 10.0f ) ;
if ( scroll_dir . x ! = 0.0f & & window - > ScrollbarX )
{
SetWindowScrollX ( window , ImFloor ( window - > Scroll . x + scroll_dir . x * scroll_speed ) ) ;
g . NavMoveFromClampedRefRect = true ;
}
if ( scroll_dir . y ! = 0.0f )
{
SetWindowScrollY ( window , ImFloor ( window - > Scroll . y + scroll_dir . y * scroll_speed ) ) ;
g . NavMoveFromClampedRefRect = true ;
}
}
// Reset search results
g . NavMoveResultLocal . Clear ( ) ;
g . NavMoveResultLocalVisibleSet . Clear ( ) ;
g . NavMoveResultOther . Clear ( ) ;
// When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
if ( g . NavMoveRequest & & g . NavMoveFromClampedRefRect & & g . NavLayer = = 0 )
{
ImGuiWindow * window = g . NavWindow ;
ImRect window_rect_rel ( window - > InnerMainRect . Min - window - > Pos - ImVec2 ( 1 , 1 ) , window - > InnerMainRect . Max - window - > Pos + ImVec2 ( 1 , 1 ) ) ;
if ( ! window_rect_rel . Contains ( window - > NavRectRel [ g . NavLayer ] ) )
{
float pad = window - > CalcFontSize ( ) * 0.5f ;
window_rect_rel . Expand ( ImVec2 ( - ImMin ( window_rect_rel . GetWidth ( ) , pad ) , - ImMin ( window_rect_rel . GetHeight ( ) , pad ) ) ) ; // Terrible approximation for the intent of starting navigation from first fully visible item
window - > NavRectRel [ g . NavLayer ] . ClipWith ( window_rect_rel ) ;
g . NavId = 0 ;
}
g . NavMoveFromClampedRefRect = false ;
}
// 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)
ImRect nav_rect_rel = ( g . NavWindow & & ! g . NavWindow - > NavRectRel [ g . NavLayer ] . IsInverted ( ) ) ? g . NavWindow - > NavRectRel [ g . NavLayer ] : ImRect ( 0 , 0 , 0 , 0 ) ;
g . NavScoringRectScreen = g . NavWindow ? ImRect ( g . NavWindow - > Pos + nav_rect_rel . Min , g . NavWindow - > Pos + nav_rect_rel . Max ) : GetViewportRect ( ) ;
g . NavScoringRectScreen . TranslateY ( nav_scoring_rect_offset_y ) ;
g . NavScoringRectScreen . Min . x = ImMin ( g . NavScoringRectScreen . Min . x + 1.0f , g . NavScoringRectScreen . Max . x ) ;
g . NavScoringRectScreen . Max . x = g . NavScoringRectScreen . Min . x ;
IM_ASSERT ( ! g . NavScoringRectScreen . IsInverted ( ) ) ; // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
//g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
g . NavScoringCount = 0 ;
# if IMGUI_DEBUG_NAV_RECTS
if ( g . NavWindow ) { for ( int layer = 0 ; layer < 2 ; layer + + ) GetOverlayDrawList ( ) - > AddRect ( g . NavWindow - > Pos + g . NavWindow - > NavRectRel [ layer ] . Min , g . NavWindow - > Pos + g . NavWindow - > NavRectRel [ layer ] . Max , IM_COL32 ( 255 , 200 , 0 , 255 ) ) ; } // [DEBUG]
if ( g . NavWindow ) { ImU32 col = ( g . NavWindow - > HiddenFrames = = 0 ) ? IM_COL32 ( 255 , 0 , 255 , 255 ) : IM_COL32 ( 255 , 0 , 0 , 255 ) ; ImVec2 p = NavCalcPreferredRefPos ( ) ; char buf [ 32 ] ; ImFormatString ( buf , 32 , " %d " , g . NavLayer ) ; g . OverlayDrawList . AddCircleFilled ( p , 3.0f , col ) ; g . OverlayDrawList . AddText ( NULL , 13.0f , p + ImVec2 ( 8 , - 4 ) , col , buf ) ; }
# endif
}
static void ImGui : : NavUpdateMoveResult ( )
static void ImGui : : NavUpdateMoveResult ( )
{
{