Updated ImGui.

This commit is contained in:
Бранимир Караџић 2019-07-17 21:02:10 -07:00
parent afe86e624d
commit cf05c7d2b1
5 changed files with 441 additions and 424 deletions

View File

@ -75,7 +75,6 @@ CODE
// [SECTION] TOOLTIPS // [SECTION] TOOLTIPS
// [SECTION] POPUPS // [SECTION] POPUPS
// [SECTION] KEYBOARD/GAMEPAD NAVIGATION // [SECTION] KEYBOARD/GAMEPAD NAVIGATION
// [SECTION] COLUMNS
// [SECTION] DRAG AND DROP // [SECTION] DRAG AND DROP
// [SECTION] LOGGING/CAPTURING // [SECTION] LOGGING/CAPTURING
// [SECTION] SETTINGS // [SECTION] SETTINGS
@ -8666,394 +8665,6 @@ void ImGui::NavUpdateWindowingList()
PopStyleVar(); PopStyleVar();
} }
//-----------------------------------------------------------------------------
// [SECTION] COLUMNS
// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system.
//-----------------------------------------------------------------------------
void ImGui::NextColumn()
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems || window->DC.CurrentColumns == NULL)
return;
ImGuiContext& g = *GImGui;
ImGuiColumns* columns = window->DC.CurrentColumns;
if (columns->Count == 1)
{
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
IM_ASSERT(columns->Current == 0);
return;
}
PopItemWidth();
PopClipRect();
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
if (++columns->Current < columns->Count)
{
// Columns 1+ cancel out IndentX
// FIXME-COLUMNS: Unnecessary, could be locked?
window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x;
window->DrawList->ChannelsSetCurrent(columns->Current + 1);
}
else
{
// New row/line
window->DC.ColumnsOffset.x = 0.0f;
window->DrawList->ChannelsSetCurrent(1);
columns->Current = 0;
columns->LineMinY = columns->LineMaxY;
}
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = columns->LineMinY;
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrLineTextBaseOffset = 0.0f;
PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
// FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup.
float offset_0 = GetColumnOffset(columns->Current);
float offset_1 = GetColumnOffset(columns->Current + 1);
float width = offset_1 - offset_0;
PushItemWidth(width * 0.65f);
window->WorkRect.Max.x = window->Pos.x + offset_1 - window->WindowPadding.x;
}
int ImGui::GetColumnIndex()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0;
}
int ImGui::GetColumnsCount()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1;
}
static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm)
{
return offset_norm * (columns->OffMaxX - columns->OffMinX);
}
static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset)
{
return offset / (columns->OffMaxX - columns->OffMinX);
}
static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index)
{
// Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
// window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x;
x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
return x;
}
float ImGui::GetColumnOffset(int column_index)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
IM_ASSERT(column_index < columns->Columns.Size);
const float t = columns->Columns[column_index].OffsetNorm;
const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
return x_offset;
}
static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false)
{
if (column_index < 0)
column_index = columns->Current;
float offset_norm;
if (before_resize)
offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
else
offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
return OffsetNormToPixels(columns, offset_norm);
}
float ImGui::GetColumnWidth(int column_index)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
}
void ImGui::SetColumnOffset(int column_index, float offset)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
IM_ASSERT(column_index < columns->Columns.Size);
const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX);
if (preserve_width)
SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
}
void ImGui::SetColumnWidth(int column_index, float width)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
}
void ImGui::PushColumnClipRect(int column_index)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
if (column_index < 0)
column_index = columns->Current;
ImGuiColumnData* column = &columns->Columns[column_index];
PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false);
}
// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns)
void ImGui::PushColumnsBackground()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
window->DrawList->ChannelsSetCurrent(0);
int cmd_size = window->DrawList->CmdBuffer.Size;
PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);
IM_UNUSED(cmd_size);
IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd
}
void ImGui::PopColumnsBackground()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
window->DrawList->ChannelsSetCurrent(columns->Current + 1);
PopClipRect();
}
ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id)
{
// We have few columns per window so for now we don't need bother much with turning this into a faster lookup.
for (int n = 0; n < window->ColumnsStorage.Size; n++)
if (window->ColumnsStorage[n].ID == id)
return &window->ColumnsStorage[n];
window->ColumnsStorage.push_back(ImGuiColumns());
ImGuiColumns* columns = &window->ColumnsStorage.back();
columns->ID = id;
return columns;
}
ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count)
{
ImGuiWindow* window = GetCurrentWindow();
// Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
// In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
PushID(0x11223347 + (str_id ? 0 : columns_count));
ImGuiID id = window->GetID(str_id ? str_id : "columns");
PopID();
return id;
}
void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(columns_count >= 1);
IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
// Acquire storage for the columns set
ImGuiID id = GetColumnsID(str_id, columns_count);
ImGuiColumns* columns = FindOrCreateColumns(window, id);
IM_ASSERT(columns->ID == id);
columns->Current = 0;
columns->Count = columns_count;
columns->Flags = flags;
window->DC.CurrentColumns = columns;
// Set state for first column
columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x;
columns->OffMaxX = ImMax(window->WorkRect.Max.x - window->Pos.x, columns->OffMinX + 1.0f);
columns->HostCursorPosY = window->DC.CursorPos.y;
columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;
columns->HostClipRect = window->ClipRect;
columns->HostWorkRect = window->WorkRect;
columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
window->DC.ColumnsOffset.x = 0.0f;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
// Clear data if columns count changed
if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
columns->Columns.resize(0);
// Initialize default widths
columns->IsFirstFrame = (columns->Columns.Size == 0);
if (columns->Columns.Size == 0)
{
columns->Columns.reserve(columns_count + 1);
for (int n = 0; n < columns_count + 1; n++)
{
ImGuiColumnData column;
column.OffsetNorm = n / (float)columns_count;
columns->Columns.push_back(column);
}
}
for (int n = 0; n < columns_count; n++)
{
// Compute clipping rectangle
ImGuiColumnData* column = &columns->Columns[n];
float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n));
float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
column->ClipRect.ClipWith(window->ClipRect);
}
if (columns->Count > 1)
{
window->DrawList->ChannelsSplit(1 + columns->Count);
window->DrawList->ChannelsSetCurrent(1);
PushColumnClipRect(0);
}
float offset_0 = GetColumnOffset(columns->Current);
float offset_1 = GetColumnOffset(columns->Current + 1);
float width = offset_1 - offset_0;
PushItemWidth(width * 0.65f);
window->WorkRect.Max.x = window->Pos.x + offset_1 - window->WindowPadding.x;
}
void ImGui::EndColumns()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
PopItemWidth();
if (columns->Count > 1)
{
PopClipRect();
window->DrawList->ChannelsMerge();
}
const ImGuiColumnsFlags flags = columns->Flags;
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
window->DC.CursorPos.y = columns->LineMaxY;
if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize))
window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
// Draw columns borders and handle resize
// The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy
bool is_being_resized = false;
if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
{
// We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.
const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y);
const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y);
int dragging_column = -1;
for (int n = 1; n < columns->Count; n++)
{
ImGuiColumnData* column = &columns->Columns[n];
float x = window->Pos.x + GetColumnOffset(n);
const ImGuiID column_id = columns->ID + ImGuiID(n);
const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
KeepAliveID(column_id);
if (IsClippedEx(column_hit_rect, column_id, false))
continue;
bool hovered = false, held = false;
if (!(flags & ImGuiColumnsFlags_NoResize))
{
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
if (hovered || held)
g.MouseCursor = ImGuiMouseCursor_ResizeEW;
if (held && !(column->Flags & ImGuiColumnsFlags_NoResize))
dragging_column = n;
}
// Draw column
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
const float xi = (float)(int)x;
window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
}
// Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
if (dragging_column != -1)
{
if (!columns->IsBeingResized)
for (int n = 0; n < columns->Count + 1; n++)
columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
columns->IsBeingResized = is_being_resized = true;
float x = GetDraggedColumnOffset(columns, dragging_column);
SetColumnOffset(dragging_column, x);
}
}
columns->IsBeingResized = is_being_resized;
window->WorkRect = columns->HostWorkRect;
window->DC.CurrentColumns = NULL;
window->DC.ColumnsOffset.x = 0.0f;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
}
// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
void ImGui::Columns(int columns_count, const char* id, bool border)
{
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(columns_count >= 1);
ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
//flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
ImGuiColumns* columns = window->DC.CurrentColumns;
if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
return;
if (columns != NULL)
EndColumns();
if (columns_count != 1)
BeginColumns(id, columns_count, flags);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] DRAG AND DROP // [SECTION] DRAG AND DROP
@ -10074,7 +9685,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return; return;
ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
for (int column_n = 0; column_n < columns->Columns.Size; column_n++) for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
ImGui::TreePop(); ImGui::TreePop();
} }

View File

@ -281,7 +281,7 @@ namespace ImGui
IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus().
IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes().
IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position.
IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis.
IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state
@ -1613,7 +1613,7 @@ struct ImGuiTextFilter
struct ImGuiTextBuffer struct ImGuiTextBuffer
{ {
ImVector<char> Buf; ImVector<char> Buf;
static char EmptyString[1]; IMGUI_API static char EmptyString[1];
ImGuiTextBuffer() { } ImGuiTextBuffer() { }
inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }

View File

@ -1545,28 +1545,22 @@ static void ShowDemoWindowWidgets()
static bool b = false; static bool b = false;
static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
static char str[16] = {}; static char str[16] = {};
ImGui::RadioButton("Text", &item_type, 0); ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode (w/ double-click)\0ListBox\0");
ImGui::RadioButton("Button", &item_type, 1); ImGui::SameLine();
ImGui::RadioButton("Checkbox", &item_type, 2); HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
ImGui::RadioButton("SliderFloat", &item_type, 3);
ImGui::RadioButton("InputText", &item_type, 4);
ImGui::RadioButton("InputFloat3", &item_type, 5);
ImGui::RadioButton("ColorEdit4", &item_type, 6);
ImGui::RadioButton("MenuItem", &item_type, 7);
ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 8);
ImGui::RadioButton("ListBox", &item_type, 9);
ImGui::Separator();
bool ret = false; bool ret = false;
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
if (item_type == 4) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
if (item_type == 5) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
if (item_type == 6) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
if (item_type == 7) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 8) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 9) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
if (item_type == 10){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
if (item_type == 11){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
ImGui::BulletText( ImGui::BulletText(
"Return value = %d\n" "Return value = %d\n"
"IsItemFocused() = %d\n" "IsItemFocused() = %d\n"
@ -3295,8 +3289,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::TreePop(); ImGui::TreePop();
} }
HelpMarker("Those are old settings provided for convenience.\nHowever, the _correct_ way of scaling your UI is currently to reload your font at the designed size, rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.");
static float window_scale = 1.0f; static float window_scale = 1.0f;
if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window if (ImGui::DragFloat("window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window
ImGui::SetWindowFontScale(window_scale); ImGui::SetWindowFontScale(window_scale);
ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything
ImGui::PopItemWidth(); ImGui::PopItemWidth();

View File

@ -1317,7 +1317,7 @@ struct IMGUI_API ImGuiWindow
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items
ImGuiStorage StateStorage; ImGuiStorage StateStorage;
ImVector<ImGuiColumns> ColumnsStorage; ImVector<ImGuiColumns> ColumnsStorage;
float FontWindowScale; // User scale multiplier per-window float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale()
int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back) int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back)
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
@ -1344,12 +1344,12 @@ public:
ImGuiID GetIDFromRectangle(const ImRect& r_abs); ImGuiID GetIDFromRectangle(const ImRect& r_abs);
// We don't use g.FontSize because the window may be != g.CurrentWidow. // We don't use g.FontSize because the window may be != g.CurrentWidow.
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); }
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; }
ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; }
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
}; };
// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. // Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data.
@ -1563,6 +1563,8 @@ namespace ImGui
IMGUI_API void PopColumnsBackground(); IMGUI_API void PopColumnsBackground();
IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count);
IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);
IMGUI_API float GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm);
IMGUI_API float GetColumnNormFromOffset(const ImGuiColumns* columns, float offset);
// Tab Bars // Tab Bars
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);

View File

@ -24,6 +24,7 @@ Index of this file:
// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc. // [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc.
// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. // [SECTION] Widgets: BeginTabBar, EndTabBar, etc.
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. // [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.
*/ */
@ -625,8 +626,6 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
flags |= ImGuiButtonFlags_Repeat; flags |= ImGuiButtonFlags_Repeat;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
if (pressed)
MarkItemEdited(id);
// Render // Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
@ -4854,9 +4853,6 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
if (pressed)
MarkItemEdited(id);
return pressed; return pressed;
} }
@ -7103,3 +7099,416 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
return close_button_pressed; return close_button_pressed;
} }
//-------------------------------------------------------------------------
// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.
// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system.
//-------------------------------------------------------------------------
// - GetColumnIndex()
// - GetColumnCount()
// - GetColumnOffset()
// - GetColumnWidth()
// - SetColumnOffset()
// - SetColumnWidth()
// - PushColumnClipRect() [Internal]
// - PushColumnsBackground() [Internal]
// - PopColumnsBackground() [Internal]
// - FindOrCreateColumns() [Internal]
// - GetColumnsID() [Internal]
// - BeginColumns()
// - NextColumn()
// - EndColumns()
// - Columns()
//-------------------------------------------------------------------------
int ImGui::GetColumnIndex()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0;
}
int ImGui::GetColumnsCount()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1;
}
float ImGui::GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm)
{
return offset_norm * (columns->OffMaxX - columns->OffMinX);
}
float ImGui::GetColumnNormFromOffset(const ImGuiColumns* columns, float offset)
{
return offset / (columns->OffMaxX - columns->OffMinX);
}
static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index)
{
// Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
// window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x;
x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
return x;
}
float ImGui::GetColumnOffset(int column_index)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
IM_ASSERT(column_index < columns->Columns.Size);
const float t = columns->Columns[column_index].OffsetNorm;
const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
return x_offset;
}
static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false)
{
if (column_index < 0)
column_index = columns->Current;
float offset_norm;
if (before_resize)
offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
else
offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
return ImGui::GetColumnOffsetFromNorm(columns, offset_norm);
}
float ImGui::GetColumnWidth(int column_index)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
}
void ImGui::SetColumnOffset(int column_index, float offset)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
IM_ASSERT(column_index < columns->Columns.Size);
const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX);
if (preserve_width)
SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
}
void ImGui::SetColumnWidth(int column_index, float width)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
if (column_index < 0)
column_index = columns->Current;
SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
}
void ImGui::PushColumnClipRect(int column_index)
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
if (column_index < 0)
column_index = columns->Current;
ImGuiColumnData* column = &columns->Columns[column_index];
PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false);
}
// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns)
void ImGui::PushColumnsBackground()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
window->DrawList->ChannelsSetCurrent(0);
int cmd_size = window->DrawList->CmdBuffer.Size;
PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);
IM_UNUSED(cmd_size);
IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd
}
void ImGui::PopColumnsBackground()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImGuiColumns* columns = window->DC.CurrentColumns;
window->DrawList->ChannelsSetCurrent(columns->Current + 1);
PopClipRect();
}
ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id)
{
// We have few columns per window so for now we don't need bother much with turning this into a faster lookup.
for (int n = 0; n < window->ColumnsStorage.Size; n++)
if (window->ColumnsStorage[n].ID == id)
return &window->ColumnsStorage[n];
window->ColumnsStorage.push_back(ImGuiColumns());
ImGuiColumns* columns = &window->ColumnsStorage.back();
columns->ID = id;
return columns;
}
ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count)
{
ImGuiWindow* window = GetCurrentWindow();
// Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
// In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
PushID(0x11223347 + (str_id ? 0 : columns_count));
ImGuiID id = window->GetID(str_id ? str_id : "columns");
PopID();
return id;
}
void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(columns_count >= 1);
IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
// Acquire storage for the columns set
ImGuiID id = GetColumnsID(str_id, columns_count);
ImGuiColumns* columns = FindOrCreateColumns(window, id);
IM_ASSERT(columns->ID == id);
columns->Current = 0;
columns->Count = columns_count;
columns->Flags = flags;
window->DC.CurrentColumns = columns;
columns->HostCursorPosY = window->DC.CursorPos.y;
columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;
columns->HostClipRect = window->ClipRect;
columns->HostWorkRect = window->WorkRect;
// Set state for first column
// We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect
const float column_padding = g.Style.ItemSpacing.x;
const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize));
columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f);
columns->OffMaxX = ImMin(window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f), window->WorkRect.Max.x + half_clip_extend_x) - window->Pos.x;
columns->OffMaxX = ImMax(columns->OffMaxX, columns->OffMinX + 1.0f);
columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
// Clear data if columns count changed
if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
columns->Columns.resize(0);
// Initialize default widths
columns->IsFirstFrame = (columns->Columns.Size == 0);
if (columns->Columns.Size == 0)
{
columns->Columns.reserve(columns_count + 1);
for (int n = 0; n < columns_count + 1; n++)
{
ImGuiColumnData column;
column.OffsetNorm = n / (float)columns_count;
columns->Columns.push_back(column);
}
}
for (int n = 0; n < columns_count; n++)
{
// Compute clipping rectangle
ImGuiColumnData* column = &columns->Columns[n];
float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n));
float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
column->ClipRect.ClipWith(window->ClipRect);
}
if (columns->Count > 1)
{
window->DrawList->ChannelsSplit(1 + columns->Count);
window->DrawList->ChannelsSetCurrent(1);
PushColumnClipRect(0);
}
float offset_0 = GetColumnOffset(columns->Current);
float offset_1 = GetColumnOffset(columns->Current + 1);
float width = offset_1 - offset_0;
PushItemWidth(width * 0.65f);
window->DC.ColumnsOffset.x = columns->OffMinX - window->DC.Indent.x + column_padding;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
}
void ImGui::NextColumn()
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems || window->DC.CurrentColumns == NULL)
return;
ImGuiContext& g = *GImGui;
ImGuiColumns* columns = window->DC.CurrentColumns;
if (columns->Count == 1)
{
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
IM_ASSERT(columns->Current == 0);
return;
}
PopItemWidth();
PopClipRect();
const float column_padding = g.Style.ItemSpacing.x;
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
if (++columns->Current < columns->Count)
{
// Columns 1+ ignore IndentX (by canceling it out)
// FIXME-COLUMNS: Unnecessary, could be locked?
window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding;
window->DrawList->ChannelsSetCurrent(columns->Current + 1);
}
else
{
// New row/line
// Column 0 honor IndentX
window->DC.ColumnsOffset.x = columns->OffMinX - window->DC.Indent.x + column_padding;
window->DrawList->ChannelsSetCurrent(1);
columns->Current = 0;
columns->LineMinY = columns->LineMaxY;
}
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = columns->LineMinY;
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrLineTextBaseOffset = 0.0f;
PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
// FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup.
float offset_0 = GetColumnOffset(columns->Current);
float offset_1 = GetColumnOffset(columns->Current + 1);
float width = offset_1 - offset_0;
PushItemWidth(width * 0.65f);
window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
}
void ImGui::EndColumns()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
ImGuiColumns* columns = window->DC.CurrentColumns;
IM_ASSERT(columns != NULL);
PopItemWidth();
if (columns->Count > 1)
{
PopClipRect();
window->DrawList->ChannelsMerge();
}
const ImGuiColumnsFlags flags = columns->Flags;
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
window->DC.CursorPos.y = columns->LineMaxY;
if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize))
window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
// Draw columns borders and handle resize
// The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy
bool is_being_resized = false;
if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
{
// We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.
const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y);
const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y);
int dragging_column = -1;
for (int n = 1; n < columns->Count; n++)
{
ImGuiColumnData* column = &columns->Columns[n];
float x = window->Pos.x + GetColumnOffset(n);
const ImGuiID column_id = columns->ID + ImGuiID(n);
const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
KeepAliveID(column_id);
if (IsClippedEx(column_hit_rect, column_id, false))
continue;
bool hovered = false, held = false;
if (!(flags & ImGuiColumnsFlags_NoResize))
{
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
if (hovered || held)
g.MouseCursor = ImGuiMouseCursor_ResizeEW;
if (held && !(column->Flags & ImGuiColumnsFlags_NoResize))
dragging_column = n;
}
// Draw column
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
const float xi = (float)(int)x;
window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
}
// Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
if (dragging_column != -1)
{
if (!columns->IsBeingResized)
for (int n = 0; n < columns->Count + 1; n++)
columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
columns->IsBeingResized = is_being_resized = true;
float x = GetDraggedColumnOffset(columns, dragging_column);
SetColumnOffset(dragging_column, x);
}
}
columns->IsBeingResized = is_being_resized;
window->WorkRect = columns->HostWorkRect;
window->DC.CurrentColumns = NULL;
window->DC.ColumnsOffset.x = 0.0f;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
}
// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
void ImGui::Columns(int columns_count, const char* id, bool border)
{
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(columns_count >= 1);
ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
//flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
ImGuiColumns* columns = window->DC.CurrentColumns;
if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
return;
if (columns != NULL)
EndColumns();
if (columns_count != 1)
BeginColumns(id, columns_count, flags);
}
//-------------------------------------------------------------------------