|
@@ -1543,7 +1543,9 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
|
|
//-------------------------------------------------------------------------
|
|
|
// [SECTION] Widgets: ComboBox
|
|
|
//-------------------------------------------------------------------------
|
|
|
+// - CalcMaxPopupHeightFromItemCount() [Internal]
|
|
|
// - BeginCombo()
|
|
|
+// - BeginComboPopup() [Internal]
|
|
|
// - EndCombo()
|
|
|
// - Combo()
|
|
|
//-------------------------------------------------------------------------
|
|
@@ -1558,81 +1560,91 @@ static float CalcMaxPopupHeightFromItemCount(int items_count)
|
|
|
|
|
|
bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags)
|
|
|
{
|
|
|
- // Always consume the SetNextWindowSizeConstraint() call in our early return paths
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0;
|
|
|
- g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint;
|
|
|
-
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
+
|
|
|
+ ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags;
|
|
|
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
|
|
|
if (window->SkipItems)
|
|
|
return false;
|
|
|
|
|
|
- IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together
|
|
|
-
|
|
|
const ImGuiStyle& style = g.Style;
|
|
|
const ImGuiID id = window->GetID(label);
|
|
|
+ IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together
|
|
|
|
|
|
const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
|
|
|
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
|
|
- const float expected_w = CalcItemWidth();
|
|
|
- const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w;
|
|
|
- const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
|
|
|
- const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
|
|
|
+ const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth();
|
|
|
+ const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
|
|
|
+ const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
|
|
|
ItemSize(total_bb, style.FramePadding.y);
|
|
|
- if (!ItemAdd(total_bb, id, &frame_bb))
|
|
|
+ if (!ItemAdd(total_bb, id, &bb))
|
|
|
return false;
|
|
|
|
|
|
+ // Open on click
|
|
|
bool hovered, held;
|
|
|
- bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held);
|
|
|
-
|
|
|
+ bool pressed = ButtonBehavior(bb, id, &hovered, &held);
|
|
|
const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id);
|
|
|
bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None);
|
|
|
+ if ((pressed || g.NavActivateId == id) && !popup_open)
|
|
|
+ {
|
|
|
+ OpenPopupEx(popup_id, ImGuiPopupFlags_None);
|
|
|
+ popup_open = true;
|
|
|
+ }
|
|
|
|
|
|
+ // Render shape
|
|
|
const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
|
|
|
- const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size);
|
|
|
- RenderNavHighlight(frame_bb, id);
|
|
|
+ const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size);
|
|
|
+ RenderNavHighlight(bb, id);
|
|
|
if (!(flags & ImGuiComboFlags_NoPreview))
|
|
|
- window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft);
|
|
|
+ window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft);
|
|
|
if (!(flags & ImGuiComboFlags_NoArrowButton))
|
|
|
{
|
|
|
ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
|
|
ImU32 text_col = GetColorU32(ImGuiCol_Text);
|
|
|
- window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight);
|
|
|
- if (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x)
|
|
|
- RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f);
|
|
|
+ window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight);
|
|
|
+ if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x)
|
|
|
+ RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f);
|
|
|
}
|
|
|
- RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding);
|
|
|
+ RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding);
|
|
|
+
|
|
|
+ // Render preview and label
|
|
|
if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
|
|
|
{
|
|
|
- ImVec2 preview_pos = frame_bb.Min + style.FramePadding;
|
|
|
if (g.LogEnabled)
|
|
|
LogSetNextTextDecoration("{", "}");
|
|
|
- RenderTextClipped(preview_pos, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f, 0.0f));
|
|
|
+ RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL);
|
|
|
}
|
|
|
if (label_size.x > 0)
|
|
|
- RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
|
|
|
-
|
|
|
- if ((pressed || g.NavActivateId == id) && !popup_open)
|
|
|
- {
|
|
|
- if (window->DC.NavLayerCurrent == 0)
|
|
|
- window->NavLastIds[0] = id;
|
|
|
- OpenPopupEx(popup_id, ImGuiPopupFlags_None);
|
|
|
- popup_open = true;
|
|
|
- }
|
|
|
+ RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label);
|
|
|
|
|
|
if (!popup_open)
|
|
|
return false;
|
|
|
|
|
|
- if (has_window_size_constraint)
|
|
|
+ g.NextWindowData.Flags = backup_next_window_data_flags;
|
|
|
+ return BeginComboPopup(popup_id, bb, flags);
|
|
|
+}
|
|
|
+
|
|
|
+bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags)
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None))
|
|
|
+ {
|
|
|
+ g.NextWindowData.ClearFlags();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set popup size
|
|
|
+ float w = bb.GetWidth();
|
|
|
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
|
|
|
{
|
|
|
- g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
|
|
|
g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if ((flags & ImGuiComboFlags_HeightMask_) == 0)
|
|
|
flags |= ImGuiComboFlags_HeightRegular;
|
|
|
- IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one
|
|
|
+ IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one
|
|
|
int popup_max_height_in_items = -1;
|
|
|
if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8;
|
|
|
else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
|
|
@@ -1640,30 +1652,27 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
|
|
|
SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
|
|
|
}
|
|
|
|
|
|
+ // This is essentially a specialized version of BeginPopupEx()
|
|
|
char name[16];
|
|
|
ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
|
|
|
|
|
|
- // Position the window given a custom constraint (peak into expected window size so we can position it)
|
|
|
- // This might be easier to express with an hypothetical SetNextWindowPosConstraints() function.
|
|
|
+ // Set position given a custom constraint (peak into expected window size so we can position it)
|
|
|
+ // FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function?
|
|
|
+ // FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()?
|
|
|
if (ImGuiWindow* popup_window = FindWindowByName(name))
|
|
|
if (popup_window->WasActive)
|
|
|
{
|
|
|
// Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us.
|
|
|
ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window);
|
|
|
- if (flags & ImGuiComboFlags_PopupAlignLeft)
|
|
|
- popup_window->AutoPosLastDirection = ImGuiDir_Left; // "Below, Toward Left"
|
|
|
- else
|
|
|
- popup_window->AutoPosLastDirection = ImGuiDir_Down; // "Below, Toward Right (default)"
|
|
|
- ImRect r_outer = GetWindowAllowedExtentRect(popup_window);
|
|
|
- ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox);
|
|
|
+ popup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)"
|
|
|
+ ImRect r_outer = GetPopupAllowedExtentRect(popup_window);
|
|
|
+ ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox);
|
|
|
SetNextWindowPos(pos);
|
|
|
}
|
|
|
|
|
|
// We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx()
|
|
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove;
|
|
|
-
|
|
|
- // Horizontally align ourselves with the framed text
|
|
|
- PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y));
|
|
|
+ PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text
|
|
|
bool ret = Begin(name, NULL, window_flags);
|
|
|
PopStyleVar();
|
|
|
if (!ret)
|
|
@@ -7837,7 +7846,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
|
|
else
|
|
|
{
|
|
|
IM_ASSERT(tab->Window == NULL);
|
|
|
- tab->NameOffset = (ImS16)tab_bar->TabsNames.size();
|
|
|
+ tab->NameOffset = (ImS32)tab_bar->TabsNames.size();
|
|
|
tab_bar->TabsNames.append(label, label + strlen(label) + 1); // Append name _with_ the zero-terminator.
|
|
|
}
|
|
|
|