Merge commit '5dd98340099b3f44e06208a3124182bcf818a77e' into refact_and_update_sdl_imgui

This commit is contained in:
2024-04-15 18:19:01 +02:00
37 changed files with 2390 additions and 1087 deletions

View File

@ -1,4 +1,4 @@
// dear imgui, v1.90.1
// dear imgui, v1.90.6 WIP
// (tables and columns code)
/*
@ -24,8 +24,9 @@ Index of this file:
*/
// Navigating this file:
// - In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
//-----------------------------------------------------------------------------
// [SECTION] Commentary
@ -227,6 +228,7 @@ Index of this file:
#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_')
#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
@ -498,7 +500,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->DeclColumnsCount = table->AngledHeadersCount = 0;
if (previous_frame_active + 1 < g.FrameCount)
table->IsActiveIdInTable = false;
temp_data->AngledheadersExtraWidth = 0.0f;
table->AngledHeadersHeight = 0.0f;
temp_data->AngledHeadersExtraWidth = 0.0f;
// Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders()
table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong);
@ -1066,6 +1069,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column.
// - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow.
// - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter.
const float previous_instance_work_min_x = column->WorkMinX;
column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1;
column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max
column->ItemWidth = ImTrunc(column->WidthGiven * 0.65f);
@ -1118,8 +1122,22 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// column->WorkMinX = ImLerp(column->WorkMinX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f);
// Reset content width variables
column->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX;
column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX;
if (table->InstanceCurrent == 0)
{
column->ContentMaxXFrozen = column->WorkMinX;
column->ContentMaxXUnfrozen = column->WorkMinX;
column->ContentMaxXHeadersUsed = column->WorkMinX;
column->ContentMaxXHeadersIdeal = column->WorkMinX;
}
else
{
// As we store an absolute value to make per-cell updates faster, we need to offset values used for width computation.
const float offset_from_previous_instance = column->WorkMinX - previous_instance_work_min_x;
column->ContentMaxXFrozen += offset_from_previous_instance;
column->ContentMaxXUnfrozen += offset_from_previous_instance;
column->ContentMaxXHeadersUsed += offset_from_previous_instance;
column->ContentMaxXHeadersIdeal += offset_from_previous_instance;
}
// Don't decrement auto-fit counters until container window got a chance to submit its items
if (table->HostSkipItems == false)
@ -1240,7 +1258,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent);
const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS;
const float hit_y1 = (table->FreezeRowsCount >= 1 ? table->OuterRect.Min.y : table->WorkRect.Min.y) + table->AngledHeadersHeight;
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight);
const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight - table->AngledHeadersHeight);
const float hit_y2_head = hit_y1 + table_instance->LastTopHeadersRowHeight;
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
@ -1344,7 +1362,7 @@ void ImGui::EndTable()
max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border);
if (table->ResizedColumn != -1)
max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2);
table->InnerWindow->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledheadersExtraWidth;
table->InnerWindow->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledHeadersExtraWidth;
}
// Pop clipping rect
@ -1462,7 +1480,7 @@ void ImGui::EndTable()
}
else if (temp_data->UserOuterSize.x <= 0.0f)
{
const float decoration_size = table->TempData->AngledheadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f);
const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f);
outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x);
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth));
}
@ -1567,6 +1585,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
}
// Store name (append with zero-terminator in contiguous buffer)
// FIXME: If we recorded the number of \n in names we could compute header row height
column->NameOffset = -1;
if (label != NULL && label[0] != 0)
{
@ -1889,7 +1908,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
if (is_visible)
{
// Update data for TableGetHoveredRow()
if (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2)
if (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2 && table_instance->HoveredRowNext < 0)
table_instance->HoveredRowNext = table->CurrentRow;
// Decide of background color for the row
@ -2154,6 +2173,8 @@ void ImGui::TableEndCell(ImGuiTable* table)
// - TableSetColumnWidthAutoAll() [Internal]
// - TableUpdateColumnsWeightFromWidth() [Internal]
//-------------------------------------------------------------------------
// Note that actual columns widths are computed in TableUpdateLayout().
//-------------------------------------------------------------------------
// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis.
float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
@ -2927,6 +2948,7 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table)
// [SECTION] Tables: Headers
//-------------------------------------------------------------------------
// - TableGetHeaderRowHeight() [Internal]
// - TableGetHeaderAngledMaxLabelWidth() [Internal]
// - TableHeadersRow()
// - TableHeader()
// - TableAngledHeadersRow()
@ -2958,7 +2980,7 @@ float ImGui::TableGetHeaderAngledMaxLabelWidth()
if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
if (table->Columns[column_n].Flags & ImGuiTableColumnFlags_AngledHeader)
width = ImMax(width, CalcTextSize(TableGetColumnName(table, column_n), NULL, true).x);
return width + g.Style.CellPadding.x * 2.0f;
return width + g.Style.CellPadding.y * 2.0f; // Swap padding
}
// [Public] This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn().
@ -3082,7 +3104,7 @@ void ImGui::TableHeader(const char* label)
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
}
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
if (held)
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
@ -3180,25 +3202,25 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
// Calculate our base metrics and set angled headers data _before_ the first call to TableNextRow()
// FIXME-STYLE: Would it be better for user to submit 'max_label_width' or 'row_height' ? One can be derived from the other.
const float header_height = table->RowCellPaddingY * 2.0f + g.FontSize;
const float row_height = ImFabs(ImRotate(ImVec2(max_label_width, flip_label ? +header_height : -header_height), cos_a, sin_a).y);
const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a);
const float header_height = g.FontSize + g.Style.CellPadding.x * 2.0f;
const float row_height = ImTrunc(ImFabs(ImRotate(ImVec2(max_label_width, flip_label ? +header_height : -header_height), cos_a, sin_a).y));
table->AngledHeadersHeight = row_height;
table->AngledHeadersSlope = (sin_a != 0.0f) ? (cos_a / sin_a) : 0.0f;
const ImVec2 header_angled_vector = unit_right * (row_height / -sin_a); // vector from bottom-left to top-left, and from bottom-right to top-right
// Declare row, override and draw our own background
TableNextRow(ImGuiTableRowFlags_Headers, row_height);
TableNextColumn();
const ImRect row_r(table->WorkRect.Min.x, table->BgClipRect.Min.y, table->WorkRect.Max.x, table->RowPosY2);
table->DrawSplitter->SetCurrentChannel(draw_list, TABLE_DRAW_CHANNEL_BG0);
float clip_rect_min_x = table->BgClipRect.Min.x;
if (table->FreezeColumnsCount > 0)
clip_rect_min_x = ImMax(clip_rect_min_x, table->Columns[table->FreezeColumnsCount - 1].MaxX);
TableSetBgColor(ImGuiTableBgTarget_RowBg0, 0); // Cancel
PushClipRect(table->BgClipRect.Min, table->BgClipRect.Max, false); // Span all columns
draw_list->AddRectFilled(table->BgClipRect.Min, table->BgClipRect.Max, GetColorU32(ImGuiCol_TableHeaderBg, 0.25f)); // FIXME-STYLE: Change row background with an arbitrary color.
draw_list->AddRectFilled(ImVec2(table->BgClipRect.Min.x, row_r.Min.y), ImVec2(table->BgClipRect.Max.x, row_r.Max.y), GetColorU32(ImGuiCol_TableHeaderBg, 0.25f)); // FIXME-STYLE: Change row background with an arbitrary color.
PushClipRect(ImVec2(clip_rect_min_x, table->BgClipRect.Min.y), table->BgClipRect.Max, true); // Span all columns
const ImRect row_r(table->WorkRect.Min.x, table->BgClipRect.Min.y, table->WorkRect.Max.x, window->DC.CursorPos.y + row_height);
const ImGuiID row_id = GetID("##AngledHeaders");
ButtonBehavior(row_r, row_id, NULL, NULL);
KeepAliveID(row_id);
@ -3209,7 +3231,9 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
if (table_instance->HoveredRowLast == 0 && table->HoveredColumnBorder == -1 && (g.ActiveId == 0 || g.ActiveId == row_id || (table->IsActiveIdInTable || g.DragDropActive)))
highlight_column_n = table->HoveredColumnBody;
// Draw background and labels in first pass, then all borders.
float max_x = 0.0f;
ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
for (int pass = 0; pass < 2; pass++)
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
@ -3231,25 +3255,45 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
draw_list->AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], GetColorU32(ImGuiCol_TableHeaderBg));
if (column_n == highlight_column_n)
draw_list->AddQuadFilled(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], GetColorU32(ImGuiCol_Header)); // Highlight on hover
//draw_list->AddQuad(bg_shape[0], bg_shape[1], bg_shape[2], bg_shape[3], GetColorU32(ImGuiCol_TableBorderLight), 1.0f);
max_x = ImMax(max_x, bg_shape[3].x);
// Draw label (first draw at an offset where RenderTextXXX() function won't meddle with applying current ClipRect, then transform to final offset)
// FIXME: May be worth tidying up all those operations to make them easier to understand.
// Draw label
// - First draw at an offset where RenderTextXXX() function won't meddle with applying current ClipRect, then transform to final offset.
// - Handle multiple lines manually, as we want each lines to follow on the horizontal border, rather than see a whole block rotated.
const char* label_name = TableGetColumnName(table, column_n);
const float clip_width = max_label_width - (sin_a * table->RowCellPaddingY);
ImRect label_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width + (flip_label ? 0.0f : table->CellPaddingX), header_height + table->RowCellPaddingY));
ImVec2 label_size = CalcTextSize(label_name, NULL, true);
ImVec2 label_off = ImVec2(flip_label ? ImMax(0.0f, max_label_width - label_size.x - table->CellPaddingX) : table->CellPaddingX, table->RowCellPaddingY);
int vtx_idx_begin = draw_list->_VtxCurrentIdx;
RenderTextEllipsis(draw_list, label_r.Min + label_off, label_r.Max, label_r.Max.x, label_r.Max.x, label_name, NULL, &label_size);
//if (g.IO.KeyShift) { draw_list->AddRect(label_r.Min, label_r.Max, IM_COL32(0, 255, 0, 255), 0.0f, 0, 2.0f); }
int vtx_idx_end = draw_list->_VtxCurrentIdx;
const char* label_name_end = FindRenderedTextEnd(label_name);
const float line_off_step_x = g.FontSize / -sin_a;
float line_off_curr_x = 0.0f;
while (label_name < label_name_end)
{
const char* label_name_eol = strchr(label_name, '\n');
if (label_name_eol == NULL)
label_name_eol = label_name_end;
// Rotate and offset label
ImVec2 pivot_in = label_r.GetBL();
ImVec2 pivot_out = ImVec2(column->WorkMinX, row_r.Max.y) + (flip_label ? (unit_right * clip_width) : ImVec2(header_height, 0.0f));
ShadeVertsTransformPos(draw_list, vtx_idx_begin, vtx_idx_end, pivot_in, label_cos_a, label_sin_a, pivot_out); // Rotate and offset
// FIXME: Individual line clipping for right-most column is broken for negative angles.
ImVec2 label_size = CalcTextSize(label_name, label_name_eol);
float clip_width = max_label_width - padding.y; // Using padding.y*2.0f would be symetrical but hide more text.
float clip_height = ImMin(label_size.y, column->ClipRect.Max.x - column->WorkMinX - line_off_curr_x);
ImRect clip_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width, clip_height));
int vtx_idx_begin = draw_list->_VtxCurrentIdx;
RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, clip_r.Max.x, label_name, label_name_eol, &label_size);
int vtx_idx_end = draw_list->_VtxCurrentIdx;
// Rotate and offset label
ImVec2 pivot_in = ImVec2(window->ClipRect.Min.x, window->ClipRect.Min.y + label_size.y);
ImVec2 pivot_out = ImVec2(column->WorkMinX, row_r.Max.y);
line_off_curr_x += line_off_step_x;
pivot_out += unit_right * padding.y;
if (flip_label)
pivot_out += unit_right * (clip_width - ImMax(0.0f, clip_width - label_size.x));
pivot_out.x += flip_label ? line_off_curr_x - line_off_step_x : line_off_curr_x;
ShadeVertsTransformPos(draw_list, vtx_idx_begin, vtx_idx_end, pivot_in, label_cos_a, label_sin_a, pivot_out); // Rotate and offset
//if (g.IO.KeyShift) { ImDrawList* fg_dl = GetForegroundDrawList(); vtx_idx_begin = fg_dl->_VtxCurrentIdx; fg_dl->AddRect(clip_r.Min, clip_r.Max, IM_COL32(0, 255, 0, 255), 0.0f, 0, 2.0f); ShadeVertsTransformPos(fg_dl, vtx_idx_begin, fg_dl->_VtxCurrentIdx, pivot_in, label_cos_a, label_sin_a, pivot_out); }
// Register header width
column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX + ImCeil(line_off_curr_x);
label_name = label_name_eol + 1;
}
}
if (pass == 1)
{
@ -3259,7 +3303,7 @@ void ImGui::TableAngledHeadersRowEx(float angle, float max_label_width)
}
PopClipRect();
PopClipRect();
table->TempData->AngledheadersExtraWidth = ImMax(0.0f, max_x - table->Columns[table->RightMostEnabledColumn].MaxX);
table->TempData->AngledHeadersExtraWidth = ImMax(0.0f, max_x - table->Columns[table->RightMostEnabledColumn].MaxX);
}
//-------------------------------------------------------------------------