@ -5104,6 +5104,47 @@ static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
return ImGuiCol_WindowBg ;
}
static void CalcResizePosSizeFromAnyCorner ( ImGuiWindow * window , const ImVec2 & corner_target , const ImVec2 & corner_norm , ImVec2 * out_pos , ImVec2 * out_size )
{
ImVec2 pos_min = ImLerp ( corner_target , window - > Pos , corner_norm ) ; // Expected window upper-left
ImVec2 pos_max = ImLerp ( window - > Pos + window - > Size , corner_target , corner_norm ) ; // Expected window lower-right
ImVec2 size_expected = pos_max - pos_min ;
ImVec2 size_constrained = CalcSizeFullWithConstraint ( window , size_expected ) ;
* out_pos = pos_min ;
if ( corner_norm . x = = 0.0f )
out_pos - > x - = ( size_constrained . x - size_expected . x ) ;
if ( corner_norm . y = = 0.0f )
out_pos - > y - = ( size_constrained . y - size_expected . y ) ;
* out_size = size_constrained ;
}
struct ImGuiResizeGripDef
{
ImVec2 CornerPos ;
ImVec2 InnerDir ;
int AngleMin12 , AngleMax12 ;
} ;
const ImGuiResizeGripDef resize_grip_def [ 4 ] =
{
{ ImVec2 ( 1 , 1 ) , ImVec2 ( - 1 , - 1 ) , 0 , 3 } , // Lower right
{ ImVec2 ( 0 , 1 ) , ImVec2 ( + 1 , - 1 ) , 3 , 6 } , // Lower left
{ ImVec2 ( 0 , 0 ) , ImVec2 ( + 1 , + 1 ) , 6 , 9 } , // Upper left
{ ImVec2 ( 1 , 0 ) , ImVec2 ( - 1 , + 1 ) , 9 , 12 } , // Upper right
} ;
static ImRect GetBorderRect ( ImGuiWindow * window , int border_n , float perp_padding , float thickness )
{
ImRect rect = window - > Rect ( ) ;
if ( thickness = = 0.0f ) rect . Max - = ImVec2 ( 1 , 1 ) ;
if ( border_n = = 0 ) return ImRect ( rect . Min . x + perp_padding , rect . Min . y , rect . Max . x - perp_padding , rect . Min . y + thickness ) ;
if ( border_n = = 1 ) return ImRect ( rect . Max . x - thickness , rect . Min . y + perp_padding , rect . Max . x , rect . Max . y - perp_padding ) ;
if ( border_n = = 2 ) return ImRect ( rect . Min . x + perp_padding , rect . Max . y - thickness , rect . Max . x - perp_padding , rect . Max . y ) ;
if ( border_n = = 3 ) return ImRect ( rect . Min . x , rect . Min . y + perp_padding , rect . Min . x + thickness , rect . Max . y - perp_padding ) ;
IM_ASSERT ( 0 ) ;
return ImRect ( ) ;
}
// Push a new ImGui window to add widgets to.
// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
// - Begin/End can be called multiple times during the frame with the same window name to append content.
@ -5455,58 +5496,104 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
else
{
ImU32 resize_col = 0 ;
const float resize_corner_size = ImMax ( g . FontSize * 1.35f , window_rounding + 1.0f + g . FontSize * 0.2f ) ;
// Handle resize for: Resize Grips, Borders, Gamepad
int border_held = - 1 ;
ImU32 resize_grip_col [ 4 ] = { 0 } ;
const int resize_grip_count = ( flags & ImGuiWindowFlags_ResizeFromAnySide ) ? 2 : 1 ; // 4
const int resize_border_count = ( flags & ImGuiWindowFlags_ResizeFromAnySide ) ? 4 : 0 ;
const float grip_draw_size = ( float ) ( int ) ImMax ( g . FontSize * 1.35f , window_rounding + 1.0f + g . FontSize * 0.2f ) ;
const float grip_hover_size = ( float ) ( int ) ( grip_draw_size * 0.75f ) ;
if ( ! ( flags & ImGuiWindowFlags_AlwaysAutoResize ) & & window - > AutoFitFramesX < = 0 & & window - > AutoFitFramesY < = 0 & & ! ( flags & ImGuiWindowFlags_NoResize ) )
{
// Manual resize
// Using the FlattenChilds button flag, we make the resize button accessible even if we are hovering over a child window
const ImVec2 br = window - > Rect ( ) . GetBR ( ) ;
const ImRect resize_rect ( br - ImFloor ( ImVec2 ( resize_corner_size * 0.75f , resize_corner_size * 0.75f ) ) , br ) ;
const ImGuiID resize_id = window - > GetID ( " #RESIZE " ) ;
ImVec2 pos_target ( FLT_MAX , FLT_MAX ) ;
ImVec2 size_target ( FLT_MAX , FLT_MAX ) ;
// Manual resize grips
PushID ( " #RESIZE " ) ;
for ( int resize_grip_n = 0 ; resize_grip_n < resize_grip_count ; resize_grip_n + + )
{
const ImGuiResizeGripDef & grip = resize_grip_def [ resize_grip_n ] ;
const ImVec2 corner = ImLerp ( window - > Pos , window - > Pos + window - > Size , grip . CornerPos ) ;
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
ImRect resize_rect ( corner , corner + grip . InnerDir * grip_hover_size ) ;
resize_rect . FixInverted ( ) ;
bool hovered , held ;
ButtonBehavior ( resize_rect , resize_id , & hovered , & held , ImGuiButtonFlags_FlattenChilds | ImGuiButtonFlags_NoNavFocus ) ;
ButtonBehavior ( resize_rect , window- > GetID ( ( void * ) resize_grip_n ) , & hovered , & held , ImGuiButtonFlags_NoNavFocus ) ;
if ( hovered | | held )
g . MouseCursor = ImGuiMouseCursor_ResizeNWSE ;
g . MouseCursor = ( resize_grip_n & 1 ) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE ;
ImVec2 nav_resize_delta ( 0.0f , 0.0f ) ;
if ( g . NavWindowingTarget = = window )
if ( g . HoveredWindow = = window & & held & & g . IO . MouseDoubleClicked [ 0 ] )
{
nav_resize_delta = GetNavInputAmount2d ( 0 , ImGuiNavReadMode_Down ) ;
if ( nav_resize_delta . x ! = 0.0f | | nav_resize_delta . y ! = 0.0f )
// Manual auto-fit when double-clicking
size_target = CalcSizeFullWithConstraint ( window , size_auto_fit ) ;
ClearActiveID ( ) ;
}
else if ( held )
{
nav_resize_delta * = ImFloor ( 600 * g . IO . DeltaTime * ImMin ( g . IO . DisplayFramebufferScale . x , g . IO . DisplayFramebufferScale . y ) ) ;
g . NavDisableMouseHover = true ;
held = true ; // For coloring
// Resize from any of the four corners
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
ImVec2 corner_target = g . IO . MousePos - g . ActiveIdClickOffset + resize_rect . GetSize ( ) * grip . CornerPos ; // Corner of the window corresponding to our corner grip
CalcResizePosSizeFromAnyCorner ( window , corner_target , grip . CornerPos , & pos_target , & size_target ) ;
}
resize_grip_col [ resize_grip_n ] = GetColorU32 ( held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip ) ;
}
ImVec2 size_target ( FLT_MAX , FLT_MAX ) ;
if ( g . HoveredWindow = = window & & held & & g . IO . MouseDoubleClicked [ 0 ] )
for ( int border_n = 0 ; border_n < resize_border_count ; border_n + + )
{
// Manual auto-fit when double-clicking
size_target = size_auto_fit ;
ClearActiveID ( ) ;
const float BORDER_SIZE = 5.0f ; // FIXME: Only works _inside_ window because of HoveredWindow check.
const float BORDER_APPEAR_TIMER = 0.05f ; // Reduce visual noise
bool hovered , held ;
ImRect border_rect = GetBorderRect ( window , border_n , grip_hover_size , BORDER_SIZE ) ;
ButtonBehavior ( border_rect , window - > GetID ( ( void * ) ( border_n + 4 ) ) , & hovered , & held , ImGuiButtonFlags_FlattenChilds ) ;
if ( ( hovered & & g . HoveredIdTimer > BORDER_APPEAR_TIMER ) | | held )
{
g . MouseCursor = ( border_n & 1 ) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS ;
if ( held ) border_held = border_n ;
}
else if ( nav_resize_delta . x ! = 0.0f | | nav_resize_delta . y ! = 0.0f )
if ( held )
{
// FIXME-NAVIGATION: Should store and accumulate into a separate size buffer to handle sizing constraints properly
g . NavWindowingToggleLayer = false ;
size_target = window - > SizeFull + nav_resize_delta ;
ImVec2 border_target = window - > Pos ;
ImVec2 border_posn ;
if ( border_n = = 0 ) { border_posn = ImVec2 ( 0 , 0 ) ; border_target . y = ( g . IO . MousePos . y - g . ActiveIdClickOffset . y ) ; }
if ( border_n = = 1 ) { border_posn = ImVec2 ( 1 , 0 ) ; border_target . x = ( g . IO . MousePos . x - g . ActiveIdClickOffset . x + BORDER_SIZE ) ; }
if ( border_n = = 2 ) { border_posn = ImVec2 ( 0 , 1 ) ; border_target . y = ( g . IO . MousePos . y - g . ActiveIdClickOffset . y + BORDER_SIZE ) ; }
if ( border_n = = 3 ) { border_posn = ImVec2 ( 0 , 0 ) ; border_target . x = ( g . IO . MousePos . x - g . ActiveIdClickOffset . x ) ; }
CalcResizePosSizeFromAnyCorner ( window , border_target , border_posn , & pos_target , & size_target ) ;
}
else if ( held )
}
PopID ( ) ;
// Navigation/gamepad resize
if ( g . NavWindowingTarget = = window )
{
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
size_target = ( g . IO . MousePos - g . ActiveIdClickOffset - window - > Pos ) + resize_rect . GetSize ( ) ;
ImVec2 nav_resize_delta = GetNavInputAmount2d ( 0 , ImGuiNavReadMode_Down ) ;
if ( nav_resize_delta . x ! = 0.0f | | nav_resize_delta . y ! = 0.0f )
{
const float GAMEPAD_RESIZE_SPEED = 600.0f ;
nav_resize_delta * = ImFloor ( GAMEPAD_RESIZE_SPEED * g . IO . DeltaTime * ImMin ( g . IO . DisplayFramebufferScale . x , g . IO . DisplayFramebufferScale . y ) ) ;
g . NavDisableMouseHover = true ;
resize_grip_col [ 0 ] = GetColorU32 ( ImGuiCol_ResizeGripActive ) ;
if ( nav_resize_delta . x ! = 0.0f | | nav_resize_delta . y ! = 0.0f )
{
// FIXME-NAVIGATION: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
g . NavWindowingToggleLayer = false ;
size_target = CalcSizeFullWithConstraint ( window , window - > SizeFull + nav_resize_delta ) ;
}
}
}
if ( size_target . x ! = FLT_MAX & & size_target . y ! = FLT_MAX )
// Apply back modified position/size to window
if ( size_target . x ! = FLT_MAX )
{
window - > SizeFull = CalcSizeFullWithConstraint ( window , size_target ) ;
window - > SizeFull = size_target ;
MarkIniSettingsDirty ( window ) ;
}
if ( pos_target . x ! = FLT_MAX )
{
window - > Pos = window - > PosFloat = ImVec2 ( ( float ) ( int ) pos_target . x , ( float ) ( int ) pos_target . y ) ;
MarkIniSettingsDirty ( window ) ;
}
resize_col = GetColorU32 ( held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip ) ;
window - > Size = window - > SizeFull ;
title_bar_rect = window - > TitleBarRect ( ) ;
}
@ -5535,20 +5622,28 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if ( window - > ScrollbarY )
Scrollbar ( ImGuiLayoutType_Vertical ) ;
// Render resize grip
// (after the input handling so we don't have a frame of latency)
// Render resize grips (after their input handling so we don't have a frame of latency)
if ( ! ( flags & ImGuiWindowFlags_NoResize ) )
{
const ImVec2 br = window - > Rect ( ) . GetBR ( ) ;
window - > DrawList - > PathLineTo ( br + ImVec2 ( - resize_corner_size , - window_border_size ) ) ;
window - > DrawList - > PathLineTo ( br + ImVec2 ( - window_border_size , - resize_corner_size ) ) ;
window - > DrawList - > PathArcToFast ( ImVec2 ( br . x - window_rounding - window_border_size , br . y - window_rounding - window_border_size ) , window_rounding , 0 , 3 ) ;
window - > DrawList - > PathFillConvex ( resize_col ) ;
for ( int resize_grip_n = 0 ; resize_grip_n < resize_grip_count ; resize_grip_n + + )
{
const ImGuiResizeGripDef & grip = resize_grip_def [ resize_grip_n ] ;
const ImVec2 corner = ImLerp ( window - > Pos , window - > Pos + window - > Size , grip . CornerPos ) ;
window - > DrawList - > PathLineTo ( corner + grip . InnerDir * ( ( resize_grip_n & 1 ) ? ImVec2 ( window_border_size , grip_draw_size ) : ImVec2 ( grip_draw_size , window_border_size ) ) ) ;
window - > DrawList - > PathLineTo ( corner + grip . InnerDir * ( ( resize_grip_n & 1 ) ? ImVec2 ( grip_draw_size , window_border_size ) : ImVec2 ( window_border_size , grip_draw_size ) ) ) ;
window - > DrawList - > PathArcToFast ( ImVec2 ( corner . x + grip . InnerDir . x * ( window_rounding + window_border_size ) , corner . y + grip . InnerDir . y * ( window_rounding + window_border_size ) ) , window_rounding , grip . AngleMin12 , grip . AngleMax12 ) ;
window - > DrawList - > PathFillConvex ( resize_grip_col [ resize_grip_n ] ) ;
}
}
// Borders
if ( window_border_size > 0.0f )
window - > DrawList - > AddRect ( window - > Pos , window - > Pos + window - > Size , GetColorU32 ( ImGuiCol_Border ) , window_rounding , ImDrawCornerFlags_All , window_border_size ) ;
if ( border_held ! = - 1 )
{
ImRect border = GetBorderRect ( window , border_held , grip_draw_size , 0.0f ) ;
window - > DrawList - > AddLine ( border . Min , border . Max , GetColorU32 ( ImGuiCol_SeparatorActive ) , ImMax ( 1.0f , window_border_size ) ) ;
}
if ( style . FrameBorderSize > 0 & & ! ( flags & ImGuiWindowFlags_NoTitleBar ) )
window - > DrawList - > AddLine ( title_bar_rect . GetBL ( ) + ImVec2 ( 1 , - 1 ) , title_bar_rect . GetBR ( ) + ImVec2 ( - 1 , - 1 ) , GetColorU32 ( ImGuiCol_Border ) , style . FrameBorderSize ) ;
}