@ -65,6 +65,7 @@ CODE
// [SECTION] RENDER HELPERS
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] ERROR CHECKING
// [SECTION] LAYOUT
// [SECTION] SCROLLING
// [SECTION] TOOLTIPS
// [SECTION] POPUPS
@ -3101,102 +3102,6 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFla
return true ;
}
// Advance cursor given item size for layout.
void ImGui : : ItemSize ( const ImVec2 & size , float text_baseline_y )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( window - > SkipItems )
return ;
// We increase the height in this function to accommodate for baseline offset.
// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
const float offset_to_match_baseline_y = ( text_baseline_y > = 0 ) ? ImMax ( 0.0f , window - > DC . CurrLineTextBaseOffset - text_baseline_y ) : 0.0f ;
const float line_height = ImMax ( window - > DC . CurrLineSize . y , size . y + offset_to_match_baseline_y ) ;
// Always align ourselves on pixel boundaries
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
window - > DC . CursorPosPrevLine . x = window - > DC . CursorPos . x + size . x ;
window - > DC . CursorPosPrevLine . y = window - > DC . CursorPos . y ;
window - > DC . CursorPos . x = IM_FLOOR ( window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ) ; // Next line
window - > DC . CursorPos . y = IM_FLOOR ( window - > DC . CursorPos . y + line_height + g . Style . ItemSpacing . y ) ; // Next line
window - > DC . CursorMaxPos . x = ImMax ( window - > DC . CursorMaxPos . x , window - > DC . CursorPosPrevLine . x ) ;
window - > DC . CursorMaxPos . y = ImMax ( window - > DC . CursorMaxPos . y , window - > DC . CursorPos . y - g . Style . ItemSpacing . y ) ;
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
window - > DC . PrevLineSize . y = line_height ;
window - > DC . CurrLineSize . y = 0.0f ;
window - > DC . PrevLineTextBaseOffset = ImMax ( window - > DC . CurrLineTextBaseOffset , text_baseline_y ) ;
window - > DC . CurrLineTextBaseOffset = 0.0f ;
// Horizontal layout mode
if ( window - > DC . LayoutType = = ImGuiLayoutType_Horizontal )
SameLine ( ) ;
}
void ImGui : : ItemSize ( const ImRect & bb , float text_baseline_y )
{
ItemSize ( bb . GetSize ( ) , 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 then use a larger region for drawing/interaction, which is passed to ItemAdd().
bool ImGui : : ItemAdd ( const ImRect & bb , ImGuiID id , const ImRect * nav_bb_arg )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( id ! = 0 )
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
window - > DC . NavLayerActiveMaskNext | = window - > DC . NavLayerCurrentMask ;
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 ) ;
// [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
# ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
if ( id = = g . DebugItemPickerBreakId )
{
IM_DEBUG_BREAK ( ) ;
g . DebugItemPickerBreakId = 0 ;
}
# endif
}
window - > DC . LastItemId = id ;
window - > DC . LastItemRect = bb ;
window - > DC . LastItemStatusFlags = ImGuiItemStatusFlags_None ;
g . NextItemData . Flags = ImGuiNextItemDataFlags_None ;
# ifdef IMGUI_ENABLE_TEST_ENGINE
if ( id ! = 0 )
IMGUI_TEST_ENGINE_ITEM_ADD ( nav_bb_arg ? * nav_bb_arg : bb , id ) ;
# endif
// Clipping test
const bool is_clipped = IsClippedEx ( bb , id , false ) ;
if ( is_clipped )
return false ;
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
// 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 ) )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_HoveredRect ;
return true ;
}
// This is roughly matching the behavior of internal-facing ItemHoverable()
// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
@ -6923,88 +6828,6 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
FocusWindow ( NULL ) ;
}
void ImGui : : SetNextItemWidth ( float item_width )
{
ImGuiContext & g = * GImGui ;
g . NextItemData . Flags | = ImGuiNextItemDataFlags_HasWidth ;
g . NextItemData . Width = item_width ;
}
void ImGui : : PushItemWidth ( float item_width )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
window - > DC . ItemWidth = ( item_width = = 0.0f ? window - > ItemWidthDefault : item_width ) ;
window - > DC . ItemWidthStack . push_back ( window - > DC . ItemWidth ) ;
g . NextItemData . Flags & = ~ ImGuiNextItemDataFlags_HasWidth ;
}
void ImGui : : PushMultiItemsWidths ( int components , float w_full )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
const ImGuiStyle & style = g . Style ;
const float w_item_one = ImMax ( 1.0f , IM_FLOOR ( ( w_full - ( style . ItemInnerSpacing . x ) * ( components - 1 ) ) / ( float ) components ) ) ;
const float w_item_last = ImMax ( 1.0f , IM_FLOOR ( w_full - ( w_item_one + style . ItemInnerSpacing . x ) * ( components - 1 ) ) ) ;
window - > DC . ItemWidthStack . push_back ( w_item_last ) ;
for ( int i = 0 ; i < components - 1 ; i + + )
window - > DC . ItemWidthStack . push_back ( w_item_one ) ;
window - > DC . ItemWidth = window - > DC . ItemWidthStack . back ( ) ;
g . NextItemData . Flags & = ~ ImGuiNextItemDataFlags_HasWidth ;
}
void ImGui : : PopItemWidth ( )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . ItemWidthStack . pop_back ( ) ;
window - > DC . ItemWidth = window - > DC . ItemWidthStack . empty ( ) ? window - > ItemWidthDefault : window - > DC . ItemWidthStack . back ( ) ;
}
// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
float ImGui : : CalcItemWidth ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
float w ;
if ( g . NextItemData . Flags & ImGuiNextItemDataFlags_HasWidth )
w = g . NextItemData . Width ;
else
w = window - > DC . ItemWidth ;
if ( w < 0.0f )
{
float region_max_x = GetContentRegionMaxAbs ( ) . x ;
w = ImMax ( 1.0f , region_max_x - window - > DC . CursorPos . x + w ) ;
}
w = IM_FLOOR ( w ) ;
return w ;
}
// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
// Note that only CalcItemWidth() is publicly exposed.
// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
ImVec2 ImGui : : CalcItemSize ( ImVec2 size , float default_w , float default_h )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
ImVec2 region_max ;
if ( size . x < 0.0f | | size . y < 0.0f )
region_max = GetContentRegionMaxAbs ( ) ;
if ( size . x = = 0.0f )
size . x = default_w ;
else if ( size . x < 0.0f )
size . x = ImMax ( 4.0f , region_max . x - window - > DC . CursorPos . x + size . x ) ;
if ( size . y = = 0.0f )
size . y = default_h ;
else if ( size . y < 0.0f )
size . y = ImMax ( 4.0f , region_max . y - window - > DC . CursorPos . y + size . y ) ;
return size ;
}
void ImGui : : SetCurrentFont ( ImFont * font )
{
ImGuiContext & g = * GImGui ;
@ -7426,77 +7249,6 @@ void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class)
g . NextWindowData . WindowClass = * window_class ;
}
// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions.
ImVec2 ImGui : : GetContentRegionMax ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
ImVec2 mx = window - > ContentRegionRect . Max - window - > Pos ;
if ( window - > DC . CurrentColumns )
mx . x = window - > WorkRect . Max . x - window - > Pos . x ;
return mx ;
}
// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
ImVec2 ImGui : : GetContentRegionMaxAbs ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
ImVec2 mx = window - > ContentRegionRect . Max ;
if ( window - > DC . CurrentColumns )
mx . x = window - > WorkRect . Max . x ;
return mx ;
}
ImVec2 ImGui : : GetContentRegionAvail ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return GetContentRegionMaxAbs ( ) - window - > DC . CursorPos ;
}
// In window space (not screen space!)
ImVec2 ImGui : : GetWindowContentRegionMin ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return window - > ContentRegionRect . Min - window - > Pos ;
}
ImVec2 ImGui : : GetWindowContentRegionMax ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return window - > ContentRegionRect . Max - window - > Pos ;
}
float ImGui : : GetWindowContentRegionWidth ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return window - > ContentRegionRect . GetWidth ( ) ;
}
float ImGui : : GetTextLineHeight ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize ;
}
float ImGui : : GetTextLineHeightWithSpacing ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize + g . Style . ItemSpacing . y ;
}
float ImGui : : GetFrameHeight ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize + g . Style . FramePadding . y * 2.0f ;
}
float ImGui : : GetFrameHeightWithSpacing ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize + g . Style . FramePadding . y * 2.0f + g . Style . ItemSpacing . y ;
}
ImDrawList * ImGui : : GetWindowDrawList ( )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
@ -7539,70 +7291,10 @@ void ImGui::SetWindowFontScale(float scale)
g . FontSize = g . DrawListSharedData . FontSize = window - > CalcFontSize ( ) ;
}
// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
ImVec2 ImGui : : GetCursorPos ( )
void ImGui : : ActivateItem ( ImGuiID id )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos - window - > Pos + window - > Scroll ;
}
float ImGui : : GetCursorPosX ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos . x - window - > Pos . x + window - > Scroll . x ;
}
float ImGui : : GetCursorPosY ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos . y - window - > Pos . y + window - > Scroll . y ;
}
void ImGui : : SetCursorPos ( const ImVec2 & local_pos )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos = window - > Pos - window - > Scroll + local_pos ;
window - > DC . CursorMaxPos = ImMax ( window - > DC . CursorMaxPos , window - > DC . CursorPos ) ;
}
void ImGui : : SetCursorPosX ( float x )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos . x = window - > Pos . x - window - > Scroll . x + x ;
window - > DC . CursorMaxPos . x = ImMax ( window - > DC . CursorMaxPos . x , window - > DC . CursorPos . x ) ;
}
void ImGui : : SetCursorPosY ( float y )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos . y = window - > Pos . y - window - > Scroll . y + y ;
window - > DC . CursorMaxPos . y = ImMax ( window - > DC . CursorMaxPos . y , window - > DC . CursorPos . y ) ;
}
ImVec2 ImGui : : GetCursorStartPos ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorStartPos - window - > Pos ;
}
ImVec2 ImGui : : GetCursorScreenPos ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos ;
}
void ImGui : : SetCursorScreenPos ( const ImVec2 & pos )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos = pos ;
window - > DC . CursorMaxPos = ImMax ( window - > DC . CursorMaxPos , window - > DC . CursorPos ) ;
}
void ImGui : : ActivateItem ( ImGuiID id )
{
ImGuiContext & g = * GImGui ;
g . NavNextActivateId = id ;
ImGuiContext & g = * GImGui ;
g . NavNextActivateId = id ;
}
void ImGui : : PushFocusScope ( ImGuiID id )
@ -7727,129 +7419,6 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
return window - > ClipRect . Overlaps ( ImRect ( rect_min , rect_max ) ) ;
}
// 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.)
void ImGui : : BeginGroup ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . GroupStack . resize ( window - > DC . GroupStack . Size + 1 ) ;
ImGuiGroupData & group_data = window - > DC . GroupStack . back ( ) ;
group_data . BackupCursorPos = window - > DC . CursorPos ;
group_data . BackupCursorMaxPos = window - > DC . CursorMaxPos ;
group_data . BackupIndent = window - > DC . Indent ;
group_data . BackupGroupOffset = window - > DC . GroupOffset ;
group_data . BackupCurrLineSize = window - > DC . CurrLineSize ;
group_data . BackupCurrLineTextBaseOffset = window - > DC . CurrLineTextBaseOffset ;
group_data . BackupActiveIdIsAlive = g . ActiveIdIsAlive ;
group_data . BackupActiveIdPreviousFrameIsAlive = g . ActiveIdPreviousFrameIsAlive ;
group_data . EmitItem = true ;
window - > DC . GroupOffset . x = window - > DC . CursorPos . x - window - > Pos . x - window - > DC . ColumnsOffset . x ;
window - > DC . Indent = window - > DC . GroupOffset ;
window - > DC . CursorMaxPos = window - > DC . CursorPos ;
window - > DC . CurrLineSize = ImVec2 ( 0.0f , 0.0f ) ;
if ( g . LogEnabled )
g . LogLinePosY = - FLT_MAX ; // To enforce Log carriage return
}
void ImGui : : EndGroup ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
IM_ASSERT ( ! window - > DC . GroupStack . empty ( ) ) ; // Mismatched BeginGroup()/EndGroup() calls
ImGuiGroupData & group_data = window - > DC . GroupStack . back ( ) ;
ImRect group_bb ( group_data . BackupCursorPos , ImMax ( window - > DC . CursorMaxPos , group_data . BackupCursorPos ) ) ;
window - > DC . CursorPos = group_data . BackupCursorPos ;
window - > DC . CursorMaxPos = ImMax ( group_data . BackupCursorMaxPos , window - > DC . CursorMaxPos ) ;
window - > DC . Indent = group_data . BackupIndent ;
window - > DC . GroupOffset = group_data . BackupGroupOffset ;
window - > DC . CurrLineSize = group_data . BackupCurrLineSize ;
window - > DC . CurrLineTextBaseOffset = group_data . BackupCurrLineTextBaseOffset ;
if ( g . LogEnabled )
g . LogLinePosY = - FLT_MAX ; // To enforce Log carriage return
if ( ! group_data . EmitItem )
{
window - > DC . GroupStack . pop_back ( ) ;
return ;
}
window - > DC . CurrLineTextBaseOffset = ImMax ( window - > DC . PrevLineTextBaseOffset , group_data . BackupCurrLineTextBaseOffset ) ; // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
ItemSize ( group_bb . GetSize ( ) ) ;
ItemAdd ( group_bb , 0 ) ;
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
// Also if you grep for LastItemId you'll notice it is only used in that context.
// (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
const bool group_contains_curr_active_id = ( group_data . BackupActiveIdIsAlive ! = g . ActiveId ) & & ( g . ActiveIdIsAlive = = g . ActiveId ) & & g . ActiveId ;
const bool group_contains_prev_active_id = ! group_data . BackupActiveIdPreviousFrameIsAlive & & g . ActiveIdPreviousFrameIsAlive ;
if ( group_contains_curr_active_id )
window - > DC . LastItemId = g . ActiveId ;
else if ( group_contains_prev_active_id )
window - > DC . LastItemId = g . ActiveIdPreviousFrame ;
window - > DC . LastItemRect = group_bb ;
// Forward Edited flag
if ( group_contains_curr_active_id & & g . ActiveIdHasBeenEditedThisFrame )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_Edited ;
// Forward Deactivated flag
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_HasDeactivated ;
if ( group_contains_prev_active_id & & g . ActiveId ! = g . ActiveIdPreviousFrame )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_Deactivated ;
window - > DC . GroupStack . pop_back ( ) ;
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
}
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
// spacing_w >= 0 : enforce spacing amount
void ImGui : : SameLine ( float offset_from_start_x , float spacing_w )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
if ( offset_from_start_x ! = 0.0f )
{
if ( spacing_w < 0.0f ) spacing_w = 0.0f ;
window - > DC . CursorPos . x = window - > Pos . x - window - > Scroll . x + offset_from_start_x + spacing_w + window - > DC . GroupOffset . x + window - > DC . ColumnsOffset . x ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
else
{
if ( spacing_w < 0.0f ) spacing_w = g . Style . ItemSpacing . x ;
window - > DC . CursorPos . x = window - > DC . CursorPosPrevLine . x + spacing_w ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
window - > DC . CurrLineSize = window - > DC . PrevLineSize ;
window - > DC . CurrLineTextBaseOffset = window - > DC . PrevLineTextBaseOffset ;
}
void ImGui : : Indent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x + = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
void ImGui : : Unindent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x - = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
//-----------------------------------------------------------------------------
// [SECTION] ERROR CHECKING
@ -7863,13 +7432,13 @@ void ImGui::Unindent(float indent_w)
bool ImGui : : DebugCheckVersionAndDataLayout ( const char * version , size_t sz_io , size_t sz_style , size_t sz_vec2 , size_t sz_vec4 , size_t sz_vert , size_t sz_idx )
{
bool error = false ;
if ( strcmp ( version , IMGUI_VERSION ) ! = 0 ) { error = true ; IM_ASSERT ( strcmp ( version , IMGUI_VERSION ) = = 0 & & " Mismatched version string! " ) ; }
if ( sz_io ! = sizeof ( ImGuiIO ) ) { error = true ; IM_ASSERT ( sz_io = = sizeof ( ImGuiIO ) & & " Mismatched struct layout! " ) ; }
if ( sz_style ! = sizeof ( ImGuiStyle ) ) { error = true ; IM_ASSERT ( sz_style = = sizeof ( ImGuiStyle ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec2 ! = sizeof ( ImVec2 ) ) { error = true ; IM_ASSERT ( sz_vec2 = = sizeof ( ImVec2 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec4 ! = sizeof ( ImVec4 ) ) { error = true ; IM_ASSERT ( sz_vec4 = = sizeof ( ImVec4 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vert ! = sizeof ( ImDrawVert ) ) { error = true ; IM_ASSERT ( sz_vert = = sizeof ( ImDrawVert ) & & " Mismatched struct layout! " ) ; }
if ( sz_idx ! = sizeof ( ImDrawIdx ) ) { error = true ; IM_ASSERT ( sz_idx = = sizeof ( ImDrawIdx ) & & " Mismatched struct layout! " ) ; }
if ( strcmp ( version , IMGUI_VERSION ) ! = 0 ) { error = true ; IM_ASSERT ( strcmp ( version , IMGUI_VERSION ) = = 0 & & " Mismatched version string! " ) ; }
if ( sz_io ! = sizeof ( ImGuiIO ) ) { error = true ; IM_ASSERT ( sz_io = = sizeof ( ImGuiIO ) & & " Mismatched struct layout! " ) ; }
if ( sz_style ! = sizeof ( ImGuiStyle ) ) { error = true ; IM_ASSERT ( sz_style = = sizeof ( ImGuiStyle ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec2 ! = sizeof ( ImVec2 ) ) { error = true ; IM_ASSERT ( sz_vec2 = = sizeof ( ImVec2 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vec4 ! = sizeof ( ImVec4 ) ) { error = true ; IM_ASSERT ( sz_vec4 = = sizeof ( ImVec4 ) & & " Mismatched struct layout! " ) ; }
if ( sz_vert ! = sizeof ( ImDrawVert ) ) { error = true ; IM_ASSERT ( sz_vert = = sizeof ( ImDrawVert ) & & " Mismatched struct layout! " ) ; }
if ( sz_idx ! = sizeof ( ImDrawIdx ) ) { error = true ; IM_ASSERT ( sz_idx = = sizeof ( ImDrawIdx ) & & " Mismatched struct layout! " ) ; }
return ! error ;
}
@ -7891,7 +7460,6 @@ static void ImGui::ErrorCheckEndFrame()
IM_ASSERT_USER_ERROR ( g . CurrentWindowStack . Size = = 1 , " Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much? " ) ;
}
}
}
// Save and compare stack sizes on Begin()/End() to detect usage errors
@ -7916,6 +7484,477 @@ static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool
IM_ASSERT ( p = = window - > DC . StackSizesBackup + IM_ARRAYSIZE ( window - > DC . StackSizesBackup ) ) ;
}
//-----------------------------------------------------------------------------
// [SECTION] LAYOUT
//-----------------------------------------------------------------------------
// - ItemSize()
// - ItemAdd()
// - SameLine()
// - GetCursorScreenPos()
// - SetCursorScreenPos()
// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
// - GetCursorStartPos()
// - Indent()
// - Unindent()
// - SetNextItemWidth()
// - PushItemWidth()
// - PushMultiItemsWidths()
// - PopItemWidth()
// - CalcItemWidth()
// - CalcItemSize()
// - GetTextLineHeight()
// - GetTextLineHeightWithSpacing()
// - GetFrameHeight()
// - GetFrameHeightWithSpacing()
// - GetContentRegionMax()
// - GetContentRegionMaxAbs() [Internal]
// - GetContentRegionAvail(),
// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
// - GetWindowContentRegionWidth()
// - BeginGroup()
// - EndGroup()
// Also see in imgui_widgets: tab bars, columns.
//-----------------------------------------------------------------------------
// Advance cursor given item size for layout.
void ImGui : : ItemSize ( const ImVec2 & size , float text_baseline_y )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( window - > SkipItems )
return ;
// We increase the height in this function to accommodate for baseline offset.
// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
const float offset_to_match_baseline_y = ( text_baseline_y > = 0 ) ? ImMax ( 0.0f , window - > DC . CurrLineTextBaseOffset - text_baseline_y ) : 0.0f ;
const float line_height = ImMax ( window - > DC . CurrLineSize . y , size . y + offset_to_match_baseline_y ) ;
// Always align ourselves on pixel boundaries
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
window - > DC . CursorPosPrevLine . x = window - > DC . CursorPos . x + size . x ;
window - > DC . CursorPosPrevLine . y = window - > DC . CursorPos . y ;
window - > DC . CursorPos . x = IM_FLOOR ( window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ) ; // Next line
window - > DC . CursorPos . y = IM_FLOOR ( window - > DC . CursorPos . y + line_height + g . Style . ItemSpacing . y ) ; // Next line
window - > DC . CursorMaxPos . x = ImMax ( window - > DC . CursorMaxPos . x , window - > DC . CursorPosPrevLine . x ) ;
window - > DC . CursorMaxPos . y = ImMax ( window - > DC . CursorMaxPos . y , window - > DC . CursorPos . y - g . Style . ItemSpacing . y ) ;
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
window - > DC . PrevLineSize . y = line_height ;
window - > DC . CurrLineSize . y = 0.0f ;
window - > DC . PrevLineTextBaseOffset = ImMax ( window - > DC . CurrLineTextBaseOffset , text_baseline_y ) ;
window - > DC . CurrLineTextBaseOffset = 0.0f ;
// Horizontal layout mode
if ( window - > DC . LayoutType = = ImGuiLayoutType_Horizontal )
SameLine ( ) ;
}
void ImGui : : ItemSize ( const ImRect & bb , float text_baseline_y )
{
ItemSize ( bb . GetSize ( ) , 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 then use a larger region for drawing/interaction, which is passed to ItemAdd().
bool ImGui : : ItemAdd ( const ImRect & bb , ImGuiID id , const ImRect * nav_bb_arg )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
if ( id ! = 0 )
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
window - > DC . NavLayerActiveMaskNext | = window - > DC . NavLayerCurrentMask ;
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 ) ;
// [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
# ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
if ( id = = g . DebugItemPickerBreakId )
{
IM_DEBUG_BREAK ( ) ;
g . DebugItemPickerBreakId = 0 ;
}
# endif
}
window - > DC . LastItemId = id ;
window - > DC . LastItemRect = bb ;
window - > DC . LastItemStatusFlags = ImGuiItemStatusFlags_None ;
g . NextItemData . Flags = ImGuiNextItemDataFlags_None ;
# ifdef IMGUI_ENABLE_TEST_ENGINE
if ( id ! = 0 )
IMGUI_TEST_ENGINE_ITEM_ADD ( nav_bb_arg ? * nav_bb_arg : bb , id ) ;
# endif
// Clipping test
const bool is_clipped = IsClippedEx ( bb , id , false ) ;
if ( is_clipped )
return false ;
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
// 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 ) )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_HoveredRect ;
return true ;
}
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
// spacing_w >= 0 : enforce spacing amount
void ImGui : : SameLine ( float offset_from_start_x , float spacing_w )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
ImGuiContext & g = * GImGui ;
if ( offset_from_start_x ! = 0.0f )
{
if ( spacing_w < 0.0f ) spacing_w = 0.0f ;
window - > DC . CursorPos . x = window - > Pos . x - window - > Scroll . x + offset_from_start_x + spacing_w + window - > DC . GroupOffset . x + window - > DC . ColumnsOffset . x ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
else
{
if ( spacing_w < 0.0f ) spacing_w = g . Style . ItemSpacing . x ;
window - > DC . CursorPos . x = window - > DC . CursorPosPrevLine . x + spacing_w ;
window - > DC . CursorPos . y = window - > DC . CursorPosPrevLine . y ;
}
window - > DC . CurrLineSize = window - > DC . PrevLineSize ;
window - > DC . CurrLineTextBaseOffset = window - > DC . PrevLineTextBaseOffset ;
}
ImVec2 ImGui : : GetCursorScreenPos ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos ;
}
void ImGui : : SetCursorScreenPos ( const ImVec2 & pos )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos = pos ;
window - > DC . CursorMaxPos = ImMax ( window - > DC . CursorMaxPos , window - > DC . CursorPos ) ;
}
// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
ImVec2 ImGui : : GetCursorPos ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos - window - > Pos + window - > Scroll ;
}
float ImGui : : GetCursorPosX ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos . x - window - > Pos . x + window - > Scroll . x ;
}
float ImGui : : GetCursorPosY ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorPos . y - window - > Pos . y + window - > Scroll . y ;
}
void ImGui : : SetCursorPos ( const ImVec2 & local_pos )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos = window - > Pos - window - > Scroll + local_pos ;
window - > DC . CursorMaxPos = ImMax ( window - > DC . CursorMaxPos , window - > DC . CursorPos ) ;
}
void ImGui : : SetCursorPosX ( float x )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos . x = window - > Pos . x - window - > Scroll . x + x ;
window - > DC . CursorMaxPos . x = ImMax ( window - > DC . CursorMaxPos . x , window - > DC . CursorPos . x ) ;
}
void ImGui : : SetCursorPosY ( float y )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . CursorPos . y = window - > Pos . y - window - > Scroll . y + y ;
window - > DC . CursorMaxPos . y = ImMax ( window - > DC . CursorMaxPos . y , window - > DC . CursorPos . y ) ;
}
ImVec2 ImGui : : GetCursorStartPos ( )
{
ImGuiWindow * window = GetCurrentWindowRead ( ) ;
return window - > DC . CursorStartPos - window - > Pos ;
}
void ImGui : : Indent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x + = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
void ImGui : : Unindent ( float indent_w )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . Indent . x - = ( indent_w ! = 0.0f ) ? indent_w : g . Style . IndentSpacing ;
window - > DC . CursorPos . x = window - > Pos . x + window - > DC . Indent . x + window - > DC . ColumnsOffset . x ;
}
// Affect large frame+labels widgets only.
void ImGui : : SetNextItemWidth ( float item_width )
{
ImGuiContext & g = * GImGui ;
g . NextItemData . Flags | = ImGuiNextItemDataFlags_HasWidth ;
g . NextItemData . Width = item_width ;
}
void ImGui : : PushItemWidth ( float item_width )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
window - > DC . ItemWidth = ( item_width = = 0.0f ? window - > ItemWidthDefault : item_width ) ;
window - > DC . ItemWidthStack . push_back ( window - > DC . ItemWidth ) ;
g . NextItemData . Flags & = ~ ImGuiNextItemDataFlags_HasWidth ;
}
void ImGui : : PushMultiItemsWidths ( int components , float w_full )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
const ImGuiStyle & style = g . Style ;
const float w_item_one = ImMax ( 1.0f , IM_FLOOR ( ( w_full - ( style . ItemInnerSpacing . x ) * ( components - 1 ) ) / ( float ) components ) ) ;
const float w_item_last = ImMax ( 1.0f , IM_FLOOR ( w_full - ( w_item_one + style . ItemInnerSpacing . x ) * ( components - 1 ) ) ) ;
window - > DC . ItemWidthStack . push_back ( w_item_last ) ;
for ( int i = 0 ; i < components - 1 ; i + + )
window - > DC . ItemWidthStack . push_back ( w_item_one ) ;
window - > DC . ItemWidth = window - > DC . ItemWidthStack . back ( ) ;
g . NextItemData . Flags & = ~ ImGuiNextItemDataFlags_HasWidth ;
}
void ImGui : : PopItemWidth ( )
{
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . ItemWidthStack . pop_back ( ) ;
window - > DC . ItemWidth = window - > DC . ItemWidthStack . empty ( ) ? window - > ItemWidthDefault : window - > DC . ItemWidthStack . back ( ) ;
}
// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
float ImGui : : CalcItemWidth ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
float w ;
if ( g . NextItemData . Flags & ImGuiNextItemDataFlags_HasWidth )
w = g . NextItemData . Width ;
else
w = window - > DC . ItemWidth ;
if ( w < 0.0f )
{
float region_max_x = GetContentRegionMaxAbs ( ) . x ;
w = ImMax ( 1.0f , region_max_x - window - > DC . CursorPos . x + w ) ;
}
w = IM_FLOOR ( w ) ;
return w ;
}
// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
// Note that only CalcItemWidth() is publicly exposed.
// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
ImVec2 ImGui : : CalcItemSize ( ImVec2 size , float default_w , float default_h )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
ImVec2 region_max ;
if ( size . x < 0.0f | | size . y < 0.0f )
region_max = GetContentRegionMaxAbs ( ) ;
if ( size . x = = 0.0f )
size . x = default_w ;
else if ( size . x < 0.0f )
size . x = ImMax ( 4.0f , region_max . x - window - > DC . CursorPos . x + size . x ) ;
if ( size . y = = 0.0f )
size . y = default_h ;
else if ( size . y < 0.0f )
size . y = ImMax ( 4.0f , region_max . y - window - > DC . CursorPos . y + size . y ) ;
return size ;
}
float ImGui : : GetTextLineHeight ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize ;
}
float ImGui : : GetTextLineHeightWithSpacing ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize + g . Style . ItemSpacing . y ;
}
float ImGui : : GetFrameHeight ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize + g . Style . FramePadding . y * 2.0f ;
}
float ImGui : : GetFrameHeightWithSpacing ( )
{
ImGuiContext & g = * GImGui ;
return g . FontSize + g . Style . FramePadding . y * 2.0f + g . Style . ItemSpacing . y ;
}
// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience!
// FIXME: This is in window space (not screen space!).
ImVec2 ImGui : : GetContentRegionMax ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
ImVec2 mx = window - > ContentRegionRect . Max - window - > Pos ;
if ( window - > DC . CurrentColumns )
mx . x = window - > WorkRect . Max . x - window - > Pos . x ;
return mx ;
}
// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
ImVec2 ImGui : : GetContentRegionMaxAbs ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
ImVec2 mx = window - > ContentRegionRect . Max ;
if ( window - > DC . CurrentColumns )
mx . x = window - > WorkRect . Max . x ;
return mx ;
}
ImVec2 ImGui : : GetContentRegionAvail ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return GetContentRegionMaxAbs ( ) - window - > DC . CursorPos ;
}
// In window space (not screen space!)
ImVec2 ImGui : : GetWindowContentRegionMin ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return window - > ContentRegionRect . Min - window - > Pos ;
}
ImVec2 ImGui : : GetWindowContentRegionMax ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return window - > ContentRegionRect . Max - window - > Pos ;
}
float ImGui : : GetWindowContentRegionWidth ( )
{
ImGuiWindow * window = GImGui - > CurrentWindow ;
return window - > ContentRegionRect . GetWidth ( ) ;
}
// 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.)
void ImGui : : BeginGroup ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
window - > DC . GroupStack . resize ( window - > DC . GroupStack . Size + 1 ) ;
ImGuiGroupData & group_data = window - > DC . GroupStack . back ( ) ;
group_data . BackupCursorPos = window - > DC . CursorPos ;
group_data . BackupCursorMaxPos = window - > DC . CursorMaxPos ;
group_data . BackupIndent = window - > DC . Indent ;
group_data . BackupGroupOffset = window - > DC . GroupOffset ;
group_data . BackupCurrLineSize = window - > DC . CurrLineSize ;
group_data . BackupCurrLineTextBaseOffset = window - > DC . CurrLineTextBaseOffset ;
group_data . BackupActiveIdIsAlive = g . ActiveIdIsAlive ;
group_data . BackupActiveIdPreviousFrameIsAlive = g . ActiveIdPreviousFrameIsAlive ;
group_data . EmitItem = true ;
window - > DC . GroupOffset . x = window - > DC . CursorPos . x - window - > Pos . x - window - > DC . ColumnsOffset . x ;
window - > DC . Indent = window - > DC . GroupOffset ;
window - > DC . CursorMaxPos = window - > DC . CursorPos ;
window - > DC . CurrLineSize = ImVec2 ( 0.0f , 0.0f ) ;
if ( g . LogEnabled )
g . LogLinePosY = - FLT_MAX ; // To enforce Log carriage return
}
void ImGui : : EndGroup ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = GetCurrentWindow ( ) ;
IM_ASSERT ( ! window - > DC . GroupStack . empty ( ) ) ; // Mismatched BeginGroup()/EndGroup() calls
ImGuiGroupData & group_data = window - > DC . GroupStack . back ( ) ;
ImRect group_bb ( group_data . BackupCursorPos , ImMax ( window - > DC . CursorMaxPos , group_data . BackupCursorPos ) ) ;
window - > DC . CursorPos = group_data . BackupCursorPos ;
window - > DC . CursorMaxPos = ImMax ( group_data . BackupCursorMaxPos , window - > DC . CursorMaxPos ) ;
window - > DC . Indent = group_data . BackupIndent ;
window - > DC . GroupOffset = group_data . BackupGroupOffset ;
window - > DC . CurrLineSize = group_data . BackupCurrLineSize ;
window - > DC . CurrLineTextBaseOffset = group_data . BackupCurrLineTextBaseOffset ;
if ( g . LogEnabled )
g . LogLinePosY = - FLT_MAX ; // To enforce Log carriage return
if ( ! group_data . EmitItem )
{
window - > DC . GroupStack . pop_back ( ) ;
return ;
}
window - > DC . CurrLineTextBaseOffset = ImMax ( window - > DC . PrevLineTextBaseOffset , group_data . BackupCurrLineTextBaseOffset ) ; // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
ItemSize ( group_bb . GetSize ( ) ) ;
ItemAdd ( group_bb , 0 ) ;
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
// Also if you grep for LastItemId you'll notice it is only used in that context.
// (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
const bool group_contains_curr_active_id = ( group_data . BackupActiveIdIsAlive ! = g . ActiveId ) & & ( g . ActiveIdIsAlive = = g . ActiveId ) & & g . ActiveId ;
const bool group_contains_prev_active_id = ! group_data . BackupActiveIdPreviousFrameIsAlive & & g . ActiveIdPreviousFrameIsAlive ;
if ( group_contains_curr_active_id )
window - > DC . LastItemId = g . ActiveId ;
else if ( group_contains_prev_active_id )
window - > DC . LastItemId = g . ActiveIdPreviousFrame ;
window - > DC . LastItemRect = group_bb ;
// Forward Edited flag
if ( group_contains_curr_active_id & & g . ActiveIdHasBeenEditedThisFrame )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_Edited ;
// Forward Deactivated flag
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_HasDeactivated ;
if ( group_contains_prev_active_id & & g . ActiveId ! = g . ActiveIdPreviousFrame )
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_Deactivated ;
window - > DC . GroupStack . pop_back ( ) ;
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
}
//-----------------------------------------------------------------------------
// [SECTION] SCROLLING
//-----------------------------------------------------------------------------