@ -70,6 +70,7 @@ CODE
// [SECTION] STYLING
// [SECTION] RENDER HELPERS
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] INPUTS
// [SECTION] ERROR CHECKING
// [SECTION] LAYOUT
// [SECTION] SCROLLING
@ -4767,238 +4768,6 @@ static void FindHoveredWindow()
g . HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window ;
}
// Test if mouse cursor is hovering given rectangle
// NB- Rectangle is clipped by our current clip setting
// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
bool ImGui : : IsMouseHoveringRect ( const ImVec2 & r_min , const ImVec2 & r_max , bool clip )
{
ImGuiContext & g = * GImGui ;
// Clip
ImRect rect_clipped ( r_min , r_max ) ;
if ( clip )
rect_clipped . ClipWith ( g . CurrentWindow - > ClipRect ) ;
// Expand for touch input
const ImRect rect_for_touch ( rect_clipped . Min - g . Style . TouchExtraPadding , rect_clipped . Max + g . Style . TouchExtraPadding ) ;
if ( ! rect_for_touch . Contains ( g . IO . MousePos ) )
return false ;
return true ;
}
int ImGui : : GetKeyIndex ( ImGuiKey imgui_key )
{
IM_ASSERT ( imgui_key > = 0 & & imgui_key < ImGuiKey_COUNT ) ;
ImGuiContext & g = * GImGui ;
return g . IO . KeyMap [ imgui_key ] ;
}
// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]!
// Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]!
bool ImGui : : IsKeyDown ( int user_key_index )
{
if ( user_key_index < 0 )
return false ;
ImGuiContext & g = * GImGui ;
IM_ASSERT ( user_key_index > = 0 & & user_key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
return g . IO . KeysDown [ user_key_index ] ;
}
// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
// t1 = current time (e.g.: g.Time)
// An event is triggered at:
// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
int ImGui : : CalcTypematicRepeatAmount ( float t0 , float t1 , float repeat_delay , float repeat_rate )
{
if ( t1 = = 0.0f )
return 1 ;
if ( t0 > = t1 )
return 0 ;
if ( repeat_rate < = 0.0f )
return ( t0 < repeat_delay ) & & ( t1 > = repeat_delay ) ;
const int count_t0 = ( t0 < repeat_delay ) ? - 1 : ( int ) ( ( t0 - repeat_delay ) / repeat_rate ) ;
const int count_t1 = ( t1 < repeat_delay ) ? - 1 : ( int ) ( ( t1 - repeat_delay ) / repeat_rate ) ;
const int count = count_t1 - count_t0 ;
return count ;
}
int ImGui : : GetKeyPressedAmount ( int key_index , float repeat_delay , float repeat_rate )
{
ImGuiContext & g = * GImGui ;
if ( key_index < 0 )
return 0 ;
IM_ASSERT ( key_index > = 0 & & key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
const float t = g . IO . KeysDownDuration [ key_index ] ;
return CalcTypematicRepeatAmount ( t - g . IO . DeltaTime , t , repeat_delay , repeat_rate ) ;
}
bool ImGui : : IsKeyPressed ( int user_key_index , bool repeat )
{
ImGuiContext & g = * GImGui ;
if ( user_key_index < 0 )
return false ;
IM_ASSERT ( user_key_index > = 0 & & user_key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
const float t = g . IO . KeysDownDuration [ user_key_index ] ;
if ( t = = 0.0f )
return true ;
if ( repeat & & t > g . IO . KeyRepeatDelay )
return GetKeyPressedAmount ( user_key_index , g . IO . KeyRepeatDelay , g . IO . KeyRepeatRate ) > 0 ;
return false ;
}
bool ImGui : : IsKeyReleased ( int user_key_index )
{
ImGuiContext & g = * GImGui ;
if ( user_key_index < 0 ) return false ;
IM_ASSERT ( user_key_index > = 0 & & user_key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
return g . IO . KeysDownDurationPrev [ user_key_index ] > = 0.0f & & ! g . IO . KeysDown [ user_key_index ] ;
}
bool ImGui : : IsMouseDown ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseDown [ button ] ;
}
bool ImGui : : IsMouseClicked ( ImGuiMouseButton button , bool repeat )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
const float t = g . IO . MouseDownDuration [ button ] ;
if ( t = = 0.0f )
return true ;
if ( repeat & & t > g . IO . KeyRepeatDelay )
{
// FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold.
int amount = CalcTypematicRepeatAmount ( t - g . IO . DeltaTime , t , g . IO . KeyRepeatDelay , g . IO . KeyRepeatRate * 0.50f ) ;
if ( amount > 0 )
return true ;
}
return false ;
}
bool ImGui : : IsMouseReleased ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseReleased [ button ] ;
}
bool ImGui : : IsMouseDoubleClicked ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseClickedCount [ button ] = = 2 ;
}
int ImGui : : GetMouseClickedCount ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseClickedCount [ button ] ;
}
// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
// [Internal] This doesn't test if the button is pressed
bool ImGui : : IsMouseDragPastThreshold ( ImGuiMouseButton button , float lock_threshold )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
if ( lock_threshold < 0.0f )
lock_threshold = g . IO . MouseDragThreshold ;
return g . IO . MouseDragMaxDistanceSqr [ button ] > = lock_threshold * lock_threshold ;
}
bool ImGui : : IsMouseDragging ( ImGuiMouseButton button , float lock_threshold )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
if ( ! g . IO . MouseDown [ button ] )
return false ;
return IsMouseDragPastThreshold ( button , lock_threshold ) ;
}
ImVec2 ImGui : : GetMousePos ( )
{
ImGuiContext & g = * GImGui ;
return g . IO . MousePos ;
}
// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
ImVec2 ImGui : : GetMousePosOnOpeningCurrentPopup ( )
{
ImGuiContext & g = * GImGui ;
if ( g . BeginPopupStack . Size > 0 )
return g . OpenPopupStack [ g . BeginPopupStack . Size - 1 ] . OpenMousePos ;
return g . IO . MousePos ;
}
// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
bool ImGui : : IsMousePosValid ( const ImVec2 * mouse_pos )
{
// The assert is only to silence a false-positive in XCode Static Analysis.
// Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).
IM_ASSERT ( GImGui ! = NULL ) ;
const float MOUSE_INVALID = - 256000.0f ;
ImVec2 p = mouse_pos ? * mouse_pos : GImGui - > IO . MousePos ;
return p . x > = MOUSE_INVALID & & p . y > = MOUSE_INVALID ;
}
bool ImGui : : IsAnyMouseDown ( )
{
ImGuiContext & g = * GImGui ;
for ( int n = 0 ; n < IM_ARRAYSIZE ( g . IO . MouseDown ) ; n + + )
if ( g . IO . MouseDown [ n ] )
return true ;
return false ;
}
// Return the delta from the initial clicking position while the mouse button is clicked or was just released.
// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window.
ImVec2 ImGui : : GetMouseDragDelta ( ImGuiMouseButton button , float lock_threshold )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
if ( lock_threshold < 0.0f )
lock_threshold = g . IO . MouseDragThreshold ;
if ( g . IO . MouseDown [ button ] | | g . IO . MouseReleased [ button ] )
if ( g . IO . MouseDragMaxDistanceSqr [ button ] > = lock_threshold * lock_threshold )
if ( IsMousePosValid ( & g . IO . MousePos ) & & IsMousePosValid ( & g . IO . MouseClickedPos [ button ] ) )
return g . IO . MousePos - g . IO . MouseClickedPos [ button ] ;
return ImVec2 ( 0.0f , 0.0f ) ;
}
void ImGui : : ResetMouseDragDelta ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
// NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
g . IO . MouseClickedPos [ button ] = g . IO . MousePos ;
}
ImGuiMouseCursor ImGui : : GetMouseCursor ( )
{
return GImGui - > MouseCursor ;
}
void ImGui : : SetMouseCursor ( ImGuiMouseCursor cursor_type )
{
GImGui - > MouseCursor = cursor_type ;
}
void ImGui : : CaptureKeyboardFromApp ( bool capture )
{
GImGui - > WantCaptureKeyboardNextFrame = capture ? 1 : 0 ;
}
void ImGui : : CaptureMouseFromApp ( bool capture )
{
GImGui - > WantCaptureMouseNextFrame = capture ? 1 : 0 ;
}
bool ImGui : : IsItemActive ( )
{
ImGuiContext & g = * GImGui ;
@ -7460,6 +7229,247 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
}
//-----------------------------------------------------------------------------
// [SECTION] INPUTS
//-----------------------------------------------------------------------------
// Test if mouse cursor is hovering given rectangle
// NB- Rectangle is clipped by our current clip setting
// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
bool ImGui : : IsMouseHoveringRect ( const ImVec2 & r_min , const ImVec2 & r_max , bool clip )
{
ImGuiContext & g = * GImGui ;
// Clip
ImRect rect_clipped ( r_min , r_max ) ;
if ( clip )
rect_clipped . ClipWith ( g . CurrentWindow - > ClipRect ) ;
// Expand for touch input
const ImRect rect_for_touch ( rect_clipped . Min - g . Style . TouchExtraPadding , rect_clipped . Max + g . Style . TouchExtraPadding ) ;
if ( ! rect_for_touch . Contains ( g . IO . MousePos ) )
return false ;
return true ;
}
int ImGui : : GetKeyIndex ( ImGuiKey imgui_key )
{
IM_ASSERT ( imgui_key > = 0 & & imgui_key < ImGuiKey_COUNT ) ;
ImGuiContext & g = * GImGui ;
return g . IO . KeyMap [ imgui_key ] ;
}
// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]!
// Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]!
bool ImGui : : IsKeyDown ( int user_key_index )
{
if ( user_key_index < 0 )
return false ;
ImGuiContext & g = * GImGui ;
IM_ASSERT ( user_key_index > = 0 & & user_key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
return g . IO . KeysDown [ user_key_index ] ;
}
// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
// t1 = current time (e.g.: g.Time)
// An event is triggered at:
// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
int ImGui : : CalcTypematicRepeatAmount ( float t0 , float t1 , float repeat_delay , float repeat_rate )
{
if ( t1 = = 0.0f )
return 1 ;
if ( t0 > = t1 )
return 0 ;
if ( repeat_rate < = 0.0f )
return ( t0 < repeat_delay ) & & ( t1 > = repeat_delay ) ;
const int count_t0 = ( t0 < repeat_delay ) ? - 1 : ( int ) ( ( t0 - repeat_delay ) / repeat_rate ) ;
const int count_t1 = ( t1 < repeat_delay ) ? - 1 : ( int ) ( ( t1 - repeat_delay ) / repeat_rate ) ;
const int count = count_t1 - count_t0 ;
return count ;
}
int ImGui : : GetKeyPressedAmount ( int key_index , float repeat_delay , float repeat_rate )
{
ImGuiContext & g = * GImGui ;
if ( key_index < 0 )
return 0 ;
IM_ASSERT ( key_index > = 0 & & key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
const float t = g . IO . KeysDownDuration [ key_index ] ;
return CalcTypematicRepeatAmount ( t - g . IO . DeltaTime , t , repeat_delay , repeat_rate ) ;
}
bool ImGui : : IsKeyPressed ( int user_key_index , bool repeat )
{
ImGuiContext & g = * GImGui ;
if ( user_key_index < 0 )
return false ;
IM_ASSERT ( user_key_index > = 0 & & user_key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
const float t = g . IO . KeysDownDuration [ user_key_index ] ;
if ( t = = 0.0f )
return true ;
if ( repeat & & t > g . IO . KeyRepeatDelay )
return GetKeyPressedAmount ( user_key_index , g . IO . KeyRepeatDelay , g . IO . KeyRepeatRate ) > 0 ;
return false ;
}
bool ImGui : : IsKeyReleased ( int user_key_index )
{
ImGuiContext & g = * GImGui ;
if ( user_key_index < 0 ) return false ;
IM_ASSERT ( user_key_index > = 0 & & user_key_index < IM_ARRAYSIZE ( g . IO . KeysDown ) ) ;
return g . IO . KeysDownDurationPrev [ user_key_index ] > = 0.0f & & ! g . IO . KeysDown [ user_key_index ] ;
}
bool ImGui : : IsMouseDown ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseDown [ button ] ;
}
bool ImGui : : IsMouseClicked ( ImGuiMouseButton button , bool repeat )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
const float t = g . IO . MouseDownDuration [ button ] ;
if ( t = = 0.0f )
return true ;
if ( repeat & & t > g . IO . KeyRepeatDelay )
{
// FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold.
int amount = CalcTypematicRepeatAmount ( t - g . IO . DeltaTime , t , g . IO . KeyRepeatDelay , g . IO . KeyRepeatRate * 0.50f ) ;
if ( amount > 0 )
return true ;
}
return false ;
}
bool ImGui : : IsMouseReleased ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseReleased [ button ] ;
}
bool ImGui : : IsMouseDoubleClicked ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseClickedCount [ button ] = = 2 ;
}
int ImGui : : GetMouseClickedCount ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
return g . IO . MouseClickedCount [ button ] ;
}
// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
// [Internal] This doesn't test if the button is pressed
bool ImGui : : IsMouseDragPastThreshold ( ImGuiMouseButton button , float lock_threshold )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
if ( lock_threshold < 0.0f )
lock_threshold = g . IO . MouseDragThreshold ;
return g . IO . MouseDragMaxDistanceSqr [ button ] > = lock_threshold * lock_threshold ;
}
bool ImGui : : IsMouseDragging ( ImGuiMouseButton button , float lock_threshold )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
if ( ! g . IO . MouseDown [ button ] )
return false ;
return IsMouseDragPastThreshold ( button , lock_threshold ) ;
}
ImVec2 ImGui : : GetMousePos ( )
{
ImGuiContext & g = * GImGui ;
return g . IO . MousePos ;
}
// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
ImVec2 ImGui : : GetMousePosOnOpeningCurrentPopup ( )
{
ImGuiContext & g = * GImGui ;
if ( g . BeginPopupStack . Size > 0 )
return g . OpenPopupStack [ g . BeginPopupStack . Size - 1 ] . OpenMousePos ;
return g . IO . MousePos ;
}
// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
bool ImGui : : IsMousePosValid ( const ImVec2 * mouse_pos )
{
// The assert is only to silence a false-positive in XCode Static Analysis.
// Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).
IM_ASSERT ( GImGui ! = NULL ) ;
const float MOUSE_INVALID = - 256000.0f ;
ImVec2 p = mouse_pos ? * mouse_pos : GImGui - > IO . MousePos ;
return p . x > = MOUSE_INVALID & & p . y > = MOUSE_INVALID ;
}
bool ImGui : : IsAnyMouseDown ( )
{
ImGuiContext & g = * GImGui ;
for ( int n = 0 ; n < IM_ARRAYSIZE ( g . IO . MouseDown ) ; n + + )
if ( g . IO . MouseDown [ n ] )
return true ;
return false ;
}
// Return the delta from the initial clicking position while the mouse button is clicked or was just released.
// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window.
ImVec2 ImGui : : GetMouseDragDelta ( ImGuiMouseButton button , float lock_threshold )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
if ( lock_threshold < 0.0f )
lock_threshold = g . IO . MouseDragThreshold ;
if ( g . IO . MouseDown [ button ] | | g . IO . MouseReleased [ button ] )
if ( g . IO . MouseDragMaxDistanceSqr [ button ] > = lock_threshold * lock_threshold )
if ( IsMousePosValid ( & g . IO . MousePos ) & & IsMousePosValid ( & g . IO . MouseClickedPos [ button ] ) )
return g . IO . MousePos - g . IO . MouseClickedPos [ button ] ;
return ImVec2 ( 0.0f , 0.0f ) ;
}
void ImGui : : ResetMouseDragDelta ( ImGuiMouseButton button )
{
ImGuiContext & g = * GImGui ;
IM_ASSERT ( button > = 0 & & button < IM_ARRAYSIZE ( g . IO . MouseDown ) ) ;
// NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
g . IO . MouseClickedPos [ button ] = g . IO . MousePos ;
}
ImGuiMouseCursor ImGui : : GetMouseCursor ( )
{
ImGuiContext & g = * GImGui ;
return g . MouseCursor ;
}
void ImGui : : SetMouseCursor ( ImGuiMouseCursor cursor_type )
{
ImGuiContext & g = * GImGui ;
g . MouseCursor = cursor_type ;
}
void ImGui : : CaptureKeyboardFromApp ( bool capture )
{
ImGuiContext & g = * GImGui ;
g . WantCaptureKeyboardNextFrame = capture ? 1 : 0 ;
}
void ImGui : : CaptureMouseFromApp ( bool capture )
{
ImGuiContext & g = * GImGui ;
g . WantCaptureMouseNextFrame = capture ? 1 : 0 ;
}
//-----------------------------------------------------------------------------
// [SECTION] ERROR CHECKING
//-----------------------------------------------------------------------------