ListBox: tweaked default height calculation. simplifying code internally (rework passing of full rect). Should have no visible side-effects + misc comments.

This commit is contained in:
ocornut 2021-02-03 14:16:08 +01:00
parent 90a518c501
commit e5cbf60def
5 changed files with 35 additions and 35 deletions

View File

@ -37,11 +37,12 @@ HOW TO UPDATE?
Breaking Changes: Breaking Changes:
- imgui_freetype: Removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. - imgui_freetype:
- Removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function.
Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too.
The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. - The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.
- imgui_freetype: Renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. - Renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.
- imgui_freetyoe: Renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. - Renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.
Other Changes: Other Changes:
@ -54,6 +55,7 @@ Other Changes:
- InputText: Fixed slightly off ScrollX tracking, noticeable with large values of FramePadding.x. (#3781) - InputText: Fixed slightly off ScrollX tracking, noticeable with large values of FramePadding.x. (#3781)
- InputText: Multiline: Fixed padding/cliprect not precisely matching single-line version. (#3781) - InputText: Multiline: Fixed padding/cliprect not precisely matching single-line version. (#3781)
- InputText: Multiline: Fixed FramePadding.y worth of vertical offset when aiming with mouse. - InputText: Multiline: Fixed FramePadding.y worth of vertical offset when aiming with mouse.
- ListBox: Tweaked default height calculation.
- Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut]
- Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications
other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType.

View File

@ -373,9 +373,9 @@ CODE
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details. You can read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2021/01/26 (1.81) - imgui_freetype: removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.
- imgui_freetype: renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.
- imgui_freetype: renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.
- 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018): - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):
- ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit(). - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().
- ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg

View File

@ -587,6 +587,7 @@ namespace ImGui
IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true!
// Widgets: Data Plotting // Widgets: Data Plotting
// - Consider using ImPlot (https://github.com/epezent/implot)
IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));

View File

@ -695,7 +695,7 @@ static void ShowDemoWindowWidgets()
ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4);
//static int listbox_item_current2 = 2; //static int listbox_item_current2 = 2;
//ImGui::SetNextItemWidth(-1); //ImGui::SetNextItemWidth(-FLT_MIN);
//ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
} }
@ -3146,7 +3146,7 @@ static void ShowDemoWindowPopups()
{ {
if (ImGui::Selectable("Set to zero")) value = 0.0f; if (ImGui::Selectable("Set to zero")) value = 0.0f;
if (ImGui::Selectable("Set to PI")) value = 3.1415f; if (ImGui::Selectable("Set to PI")) value = 3.1415f;
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-FLT_MIN);
ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
ImGui::EndPopup(); ImGui::EndPopup();
} }
@ -7478,7 +7478,7 @@ void ShowExampleAppDocuments(bool* p_open)
if (ImGui::BeginPopupModal("Save?")) if (ImGui::BeginPopupModal("Save?"))
{ {
ImGui::Text("Save change to the following items?"); ImGui::Text("Save change to the following items?");
ImGui::SetNextItemWidth(-1.0f); ImGui::SetNextItemWidth(-FLT_MIN);
if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6))
{ {
for (int n = 0; n < close_queue.Size; n++) for (int n = 0; n < close_queue.Size; n++)

View File

@ -6129,12 +6129,12 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags
// - ListBoxFooter() // - ListBoxFooter()
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox // FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox
// and promote using them over existing ListBox() functions, similarly to change with combo boxes. // and promote using them over existing ListBox() functions, similarly to how we now use combo boxes.
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. // FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature.
// Helper to calculate the size of a listbox and display a label on the right. // Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty"
// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" // Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height).
bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -6146,12 +6146,12 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
const ImGuiID id = GetID(label); const ImGuiID id = GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, NULL, true);
// Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. // Size default to hold ~7.25 items.
ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
ImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f));
ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
g.NextItemData.ClearFlags(); g.NextItemData.ClearFlags();
if (!IsRectVisible(bb.Min, bb.Max)) if (!IsRectVisible(bb.Min, bb.Max))
@ -6161,50 +6161,46 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
return false; return false;
} }
// FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well.
BeginGroup(); BeginGroup();
if (label_size.x > 0) if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); {
ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y);
RenderText(label_pos, label);
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size);
}
BeginChildFrame(id, frame_bb.GetSize()); BeginChildFrame(id, frame_bb.GetSize());
return true; return true;
} }
// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. // FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature.
bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
{ {
// Size default to hold ~7.25 items. // Size default to hold ~7.25 items.
// We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar.
// We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size.
// I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution.
ImGuiContext& g = *GImGui;
if (height_in_items < 0) if (height_in_items < 0)
height_in_items = ImMin(items_count, 7); height_in_items = ImMin(items_count, 7);
const ImGuiStyle& style = GetStyle();
float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f);
// We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild().
ImVec2 size; ImVec2 size;
size.x = 0.0f; size.x = 0.0f;
size.y = ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f); size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f;
return ListBoxHeader(label, size); return ListBoxHeader(label, size);
} }
// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. // FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature.
void ImGui::ListBoxFooter() void ImGui::ListBoxFooter()
{ {
ImGuiWindow * window = GetCurrentWindow(); ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched ListBoxHeader/ListBoxFooter calls. Did you test the return value of ListBoxHeader()?"); IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched ListBoxHeader/ListBoxFooter calls. Did you test the return value of ListBoxHeader()?");
ImGuiWindow* parent_window = window->ParentWindow;
const ImRect bb = parent_window->DC.LastItemRect;
const ImGuiStyle& style = GetStyle();
EndChildFrame(); EndChildFrame();
EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label
// Redeclare item size so that it includes the label (we have stored the full size in LastItemRect)
// We call SameLine() to restore DC.CurrentLine* data
SameLine();
parent_window->DC.CursorPos = bb.Min;
ItemSize(bb, style.FramePadding.y);
EndGroup();
} }
bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items)
@ -6218,7 +6214,8 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
if (!ListBoxHeader(label, items_count, height_in_items)) if (!ListBoxHeader(label, items_count, height_in_items))
return false; return false;
// Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. // Assume all items have even height (= 1 line of text). If you need items of different height,
// you can create a custom version of ListBox() in your code without using the clipper.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
bool value_changed = false; bool value_changed = false;
ImGuiListClipper clipper; ImGuiListClipper clipper;
@ -6226,12 +6223,12 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
while (clipper.Step()) while (clipper.Step())
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
{ {
const bool item_selected = (i == *current_item);
const char* item_text; const char* item_text;
if (!items_getter(data, i, &item_text)) if (!items_getter(data, i, &item_text))
item_text = "*Unknown item*"; item_text = "*Unknown item*";
PushID(i); PushID(i);
const bool item_selected = (i == *current_item);
if (Selectable(item_text, item_selected)) if (Selectable(item_text, item_selected))
{ {
*current_item = i; *current_item = i;