|
@@ -3542,7 +3542,7 @@ static bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
|
|
bool ImGui::BeginPopup(const char* str_id)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
|
|
|
+ if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
|
|
|
{
|
|
|
ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
|
|
|
return false;
|
|
@@ -4345,6 +4345,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
|
|
window->DC.ColumnsCurrent = 0;
|
|
|
window->DC.ColumnsCount = 1;
|
|
|
window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
|
|
|
+ window->DC.ColumnsStartMaxPosX = window->DC.CursorMaxPos.x;
|
|
|
window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.ColumnsStartPosY;
|
|
|
window->DC.TreeDepth = 0;
|
|
|
window->DC.StateStorage = &window->StateStorage;
|
|
@@ -4450,7 +4451,7 @@ void ImGui::End()
|
|
|
ImGuiWindow* window = g.CurrentWindow;
|
|
|
|
|
|
if (window->DC.ColumnsCount != 1) // close columns set if any is open
|
|
|
- Columns(1, "#CLOSECOLUMNS");
|
|
|
+ EndColumns();
|
|
|
PopClipRect(); // inner window clip rectangle
|
|
|
|
|
|
// Stop logging
|
|
@@ -9808,7 +9809,7 @@ void ImGui::EndGroup()
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
|
- IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
|
|
|
+ IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
|
|
|
|
|
|
ImGuiGroupData& group_data = window->DC.GroupStack.back();
|
|
|
|
|
@@ -9928,6 +9929,16 @@ int ImGui::GetColumnsCount()
|
|
|
return window->DC.ColumnsCount;
|
|
|
}
|
|
|
|
|
|
+static float OffsetNormToPixels(ImGuiWindow* window, float offset_norm)
|
|
|
+{
|
|
|
+ return offset_norm * (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
|
|
|
+}
|
|
|
+
|
|
|
+static float PixelsToOffsetNorm(ImGuiWindow* window, float offset)
|
|
|
+{
|
|
|
+ return (offset - window->DC.ColumnsMinX) / (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
|
|
|
+}
|
|
|
+
|
|
|
static float GetDraggedColumnOffset(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
|
|
@@ -9938,43 +9949,57 @@ static float GetDraggedColumnOffset(int column_index)
|
|
|
IM_ASSERT(g.ActiveId == window->DC.ColumnsSetId + ImGuiID(column_index));
|
|
|
|
|
|
float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x;
|
|
|
- x = ImClamp(x, ImGui::GetColumnOffset(column_index-1)+g.Style.ColumnsMinSpacing, ImGui::GetColumnOffset(column_index+1)-g.Style.ColumnsMinSpacing);
|
|
|
+ x = ImMax(x, ImGui::GetColumnOffset(column_index-1) + g.Style.ColumnsMinSpacing);
|
|
|
+ if ((window->DC.ColumnsFlags & ImGuiColumnsFlags_NoPreserveWidths))
|
|
|
+ x = ImMin(x, ImGui::GetColumnOffset(column_index+1) - g.Style.ColumnsMinSpacing);
|
|
|
|
|
|
- return (float)(int)x;
|
|
|
+ return x;
|
|
|
}
|
|
|
|
|
|
float ImGui::GetColumnOffset(int column_index)
|
|
|
{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
if (column_index < 0)
|
|
|
column_index = window->DC.ColumnsCurrent;
|
|
|
|
|
|
+ /*
|
|
|
if (g.ActiveId)
|
|
|
{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
if (g.ActiveId == column_id)
|
|
|
return GetDraggedColumnOffset(column_index);
|
|
|
}
|
|
|
+ */
|
|
|
|
|
|
IM_ASSERT(column_index < window->DC.ColumnsData.Size);
|
|
|
const float t = window->DC.ColumnsData[column_index].OffsetNorm;
|
|
|
const float x_offset = ImLerp(window->DC.ColumnsMinX, window->DC.ColumnsMaxX, t);
|
|
|
- return (float)(int)x_offset;
|
|
|
+ return x_offset;
|
|
|
}
|
|
|
|
|
|
void ImGui::SetColumnOffset(int column_index, float offset)
|
|
|
{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
if (column_index < 0)
|
|
|
column_index = window->DC.ColumnsCurrent;
|
|
|
|
|
|
IM_ASSERT(column_index < window->DC.ColumnsData.Size);
|
|
|
- const float t = (offset - window->DC.ColumnsMinX) / (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
|
|
|
- window->DC.ColumnsData[column_index].OffsetNorm = t;
|
|
|
+
|
|
|
+ const bool preserve_width = !(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < window->DC.ColumnsCount-1);
|
|
|
+ const float width = preserve_width ? GetColumnWidth(column_index) : 0.0f;
|
|
|
+
|
|
|
+ if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoForceWithinWindow))
|
|
|
+ offset = ImMin(offset, window->DC.ColumnsMaxX - g.Style.ColumnsMinSpacing * (window->DC.ColumnsCount - column_index));
|
|
|
+ const float offset_norm = PixelsToOffsetNorm(window, offset);
|
|
|
|
|
|
const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
- window->DC.StateStorage->SetFloat(column_id, t);
|
|
|
+ window->DC.StateStorage->SetFloat(column_id, offset_norm);
|
|
|
+ window->DC.ColumnsData[column_index].OffsetNorm = offset_norm;
|
|
|
+
|
|
|
+ if (preserve_width)
|
|
|
+ SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
|
|
|
}
|
|
|
|
|
|
float ImGui::GetColumnWidth(int column_index)
|
|
@@ -9983,8 +10008,16 @@ float ImGui::GetColumnWidth(int column_index)
|
|
|
if (column_index < 0)
|
|
|
column_index = window->DC.ColumnsCurrent;
|
|
|
|
|
|
- float w = GetColumnOffset(column_index+1) - GetColumnOffset(column_index);
|
|
|
- return w;
|
|
|
+ return OffsetNormToPixels(window, window->DC.ColumnsData[column_index+1].OffsetNorm - window->DC.ColumnsData[column_index].OffsetNorm);
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::SetColumnWidth(int column_index, float width)
|
|
|
+{
|
|
|
+ ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
+ if (column_index < 0)
|
|
|
+ column_index = window->DC.ColumnsCurrent;
|
|
|
+
|
|
|
+ SetColumnOffset(column_index+1, GetColumnOffset(column_index) + width);
|
|
|
}
|
|
|
|
|
|
static void PushColumnClipRect(int column_index)
|
|
@@ -9998,57 +10031,13 @@ static void PushColumnClipRect(int column_index)
|
|
|
ImGui::PushClipRect(ImVec2(x1,-FLT_MAX), ImVec2(x2,+FLT_MAX), true);
|
|
|
}
|
|
|
|
|
|
-void ImGui::Columns(int columns_count, const char* id, bool border)
|
|
|
+void ImGui::BeginColumns(const char* id, int columns_count, ImGuiColumnsFlags flags)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
- IM_ASSERT(columns_count >= 1);
|
|
|
-
|
|
|
- if (window->DC.ColumnsCount != 1)
|
|
|
- {
|
|
|
- if (window->DC.ColumnsCurrent != 0)
|
|
|
- ItemSize(ImVec2(0,0)); // Advance to column 0
|
|
|
- PopItemWidth();
|
|
|
- PopClipRect();
|
|
|
- window->DrawList->ChannelsMerge();
|
|
|
-
|
|
|
- window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
|
|
|
- window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;
|
|
|
- }
|
|
|
-
|
|
|
- // Draw columns borders and handle resize at the time of "closing" a columns set
|
|
|
- if (window->DC.ColumnsCount != columns_count && window->DC.ColumnsCount != 1 && window->DC.ColumnsShowBorders && !window->SkipItems)
|
|
|
- {
|
|
|
- const float y1 = window->DC.ColumnsStartPosY;
|
|
|
- const float y2 = window->DC.CursorPos.y;
|
|
|
- for (int i = 1; i < window->DC.ColumnsCount; i++)
|
|
|
- {
|
|
|
- float x = window->Pos.x + GetColumnOffset(i);
|
|
|
- const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(i);
|
|
|
- const float column_w = 4.0f;
|
|
|
- const ImRect column_rect(ImVec2(x - column_w, y1), ImVec2(x + column_w, y2));
|
|
|
- if (IsClippedEx(column_rect, &column_id, false))
|
|
|
- continue;
|
|
|
-
|
|
|
- bool hovered, held;
|
|
|
- ButtonBehavior(column_rect, column_id, &hovered, &held);
|
|
|
- if (hovered || held)
|
|
|
- g.MouseCursor = ImGuiMouseCursor_ResizeEW;
|
|
|
|
|
|
- // Draw before resize so our items positioning are in sync with the line being drawn
|
|
|
- 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);
|
|
|
-
|
|
|
- if (held)
|
|
|
- {
|
|
|
- if (g.ActiveIdIsJustActivated)
|
|
|
- g.ActiveIdClickOffset.x -= column_w; // Store from center of column line (we used a 8 wide rect for columns clicking)
|
|
|
- x = GetDraggedColumnOffset(i);
|
|
|
- SetColumnOffset(i, x);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ IM_ASSERT(columns_count > 1);
|
|
|
+ IM_ASSERT(window->DC.ColumnsCount == 1); // Nested columns are currently not supported
|
|
|
|
|
|
// 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.
|
|
@@ -10059,36 +10048,112 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
|
|
|
// Set state for first column
|
|
|
window->DC.ColumnsCurrent = 0;
|
|
|
window->DC.ColumnsCount = columns_count;
|
|
|
- window->DC.ColumnsShowBorders = border;
|
|
|
+ window->DC.ColumnsFlags = flags;
|
|
|
|
|
|
const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : window->Size.x;
|
|
|
window->DC.ColumnsMinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
|
|
|
- window->DC.ColumnsMaxX = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
|
|
|
+ //window->DC.ColumnsMaxX = content_region_width - window->Scroll.x -((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
|
|
|
+ window->DC.ColumnsMaxX = content_region_width - window->Scroll.x - window->ScrollbarSizes.x;
|
|
|
window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
|
|
|
+ window->DC.ColumnsStartMaxPosX = window->DC.CursorMaxPos.x;
|
|
|
window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.CursorPos.y;
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
|
|
|
- if (window->DC.ColumnsCount != 1)
|
|
|
+ // Cache column offsets
|
|
|
+ window->DC.ColumnsData.resize(columns_count + 1);
|
|
|
+ for (int column_index = 0; column_index < columns_count + 1; column_index++)
|
|
|
{
|
|
|
- // Cache column offsets
|
|
|
- window->DC.ColumnsData.resize(columns_count + 1);
|
|
|
- for (int column_index = 0; column_index < columns_count + 1; column_index++)
|
|
|
+ const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
+ KeepAliveID(column_id);
|
|
|
+ const float default_t = column_index / (float)window->DC.ColumnsCount;
|
|
|
+ float t = window->DC.StateStorage->GetFloat(column_id, default_t); // Cheaply store our floating point value inside the integer (could store a union into the map?)
|
|
|
+ if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoForceWithinWindow))
|
|
|
+ t = ImMin(t, PixelsToOffsetNorm(window, window->DC.ColumnsMaxX - g.Style.ColumnsMinSpacing * (window->DC.ColumnsCount - column_index)));
|
|
|
+ window->DC.ColumnsData[column_index].OffsetNorm = t;
|
|
|
+ }
|
|
|
+ window->DrawList->ChannelsSplit(window->DC.ColumnsCount);
|
|
|
+ PushColumnClipRect();
|
|
|
+ PushItemWidth(GetColumnWidth() * 0.65f);
|
|
|
+}
|
|
|
+
|
|
|
+void ImGui::EndColumns()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ ImGuiWindow* window = GetCurrentWindow();
|
|
|
+ IM_ASSERT(window->DC.ColumnsCount > 1);
|
|
|
+
|
|
|
+ PopItemWidth();
|
|
|
+ PopClipRect();
|
|
|
+ window->DrawList->ChannelsMerge();
|
|
|
+
|
|
|
+ window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
|
|
|
+ window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;
|
|
|
+ window->DC.CursorMaxPos.x = ImMax(window->DC.ColumnsStartMaxPosX, window->DC.ColumnsMaxX); // Columns don't grow parent
|
|
|
+
|
|
|
+ // Draw columns borders and handle resize
|
|
|
+ if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
|
|
|
+ {
|
|
|
+ const float y1 = window->DC.ColumnsStartPosY;
|
|
|
+ const float y2 = window->DC.CursorPos.y;
|
|
|
+ int dragging_column = -1;
|
|
|
+ for (int i = 1; i < window->DC.ColumnsCount; i++)
|
|
|
+ {
|
|
|
+ float x = window->Pos.x + GetColumnOffset(i);
|
|
|
+ const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(i);
|
|
|
+ const float column_w = 4.0f; // Width for interaction
|
|
|
+ const ImRect column_rect(ImVec2(x - column_w, y1), ImVec2(x + column_w, y2));
|
|
|
+ if (IsClippedEx(column_rect, &column_id, false))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ bool hovered = false, held = false;
|
|
|
+ if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoResize))
|
|
|
+ {
|
|
|
+ ButtonBehavior(column_rect, column_id, &hovered, &held);
|
|
|
+ if (hovered || held)
|
|
|
+ g.MouseCursor = ImGuiMouseCursor_ResizeEW;
|
|
|
+ if (held && g.ActiveIdIsJustActivated)
|
|
|
+ g.ActiveIdClickOffset.x -= column_w; // Store from center of column line (we used a 8 wide rect for columns clicking). This is used by GetDraggedColumnOffset().
|
|
|
+ if (held)
|
|
|
+ dragging_column = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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)
|
|
|
{
|
|
|
- const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
|
|
|
- KeepAliveID(column_id);
|
|
|
- const float default_t = column_index / (float)window->DC.ColumnsCount;
|
|
|
- const float t = window->DC.StateStorage->GetFloat(column_id, default_t); // Cheaply store our floating point value inside the integer (could store a union into the map?)
|
|
|
- window->DC.ColumnsData[column_index].OffsetNorm = t;
|
|
|
+ float x = GetDraggedColumnOffset(dragging_column);
|
|
|
+ SetColumnOffset(dragging_column, x);
|
|
|
}
|
|
|
- window->DrawList->ChannelsSplit(window->DC.ColumnsCount);
|
|
|
- PushColumnClipRect();
|
|
|
- PushItemWidth(GetColumnWidth() * 0.65f);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- window->DC.ColumnsData.resize(0);
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ window->DC.ColumnsSetId = 0;
|
|
|
+ window->DC.ColumnsCurrent = 0;
|
|
|
+ window->DC.ColumnsCount = 1;
|
|
|
+ window->DC.ColumnsFlags = 0;
|
|
|
+ window->DC.ColumnsData.resize(0);
|
|
|
+ window->DC.ColumnsOffsetX = 0.0f;
|
|
|
+ window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
+}
|
|
|
+
|
|
|
+// [2017/08: 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);
|
|
|
+
|
|
|
+ if (window->DC.ColumnsCount != columns_count && window->DC.ColumnsCount != 1)
|
|
|
+ EndColumns();
|
|
|
+
|
|
|
+ ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
|
|
|
+ //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
|
|
|
+ if (columns_count != 1)
|
|
|
+ BeginColumns(id, columns_count, flags);
|
|
|
}
|
|
|
|
|
|
void ImGui::Indent(float indent_w)
|