Merge branch 'master' into docking

# Conflicts:
#	imgui.cpp
#	imgui_internal.h
#	imgui_widgets.cpp
This commit is contained in:
omar 2019-05-24 21:58:17 +02:00
commit afad952450
6 changed files with 159 additions and 77 deletions

View File

@ -41,6 +41,8 @@ Other Changes:
- Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125)
- Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect
but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. but it breaks existing some layout patterns. Will return back to it when we expose Separator flags.
- Fixed InputScalar, InputScalarN, SliderScalarN, DragScalarN with non-visible label from inserting
style.ItemInnerSpacing.x worth of trailing spacing.
- Fixed InputFloatX, SliderFloatX, DragFloatX functions erroneously reporting IsItemEdited() multiple - Fixed InputFloatX, SliderFloatX, DragFloatX functions erroneously reporting IsItemEdited() multiple
times when the text input doesn't match the formatted output value (e.g. input "1" shows "1.000"). times when the text input doesn't match the formatted output value (e.g. input "1" shows "1.000").
It wasn't much of a problem because we typically use the return value instead of IsItemEdited() here. It wasn't much of a problem because we typically use the return value instead of IsItemEdited() here.
@ -48,6 +50,9 @@ Other Changes:
after EndGroup(). (#2550, #1875) after EndGroup(). (#2550, #1875)
- Fixed crash when appending with BeginMainMenuBar() more than once and no other window are showing. (#2567) - Fixed crash when appending with BeginMainMenuBar() more than once and no other window are showing. (#2567)
- Scrollbar: Very minor bounding box adjustment to cope with various border size. - Scrollbar: Very minor bounding box adjustment to cope with various border size.
- Style: Added style.WindowMenuButtonPosition (left/right, defaults to ImGuiDir_Left) to move the
collapsing/docking button to the other side of the title bar.
- Style: Made window close button cross is slightly smaller.
- ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545) - ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545)
Combine with RasterizerFlags::MonoHinting for best results. Combine with RasterizerFlags::MonoHinting for best results.
- ImFontGlyphRangesBuilder: Fixed unnecessarily over-sized buffer, which incidentally was also not - ImFontGlyphRangesBuilder: Fixed unnecessarily over-sized buffer, which incidentally was also not

View File

@ -1161,6 +1161,7 @@ ImGuiStyle::ImGuiStyle()
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
WindowMinSize = ImVec2(32,32); // Minimum window size WindowMinSize = ImVec2(32,32); // Minimum window size
WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
@ -3593,6 +3594,8 @@ void ImGui::NewFrame()
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!"); IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
for (int n = 0; n < ImGuiKey_COUNT; n++) for (int n = 0; n < ImGuiKey_COUNT; n++)
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
@ -5434,30 +5437,54 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
} }
} }
// Render title text, collapse button, close button
void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style; ImGuiStyle& style = g.Style;
ImGuiWindowFlags flags = window->Flags; ImGuiWindowFlags flags = window->Flags;
// Close & collapse button are on layer 1 (same as menus) and don't default focus const bool has_close_button = (p_open != NULL);
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse);
// Close & collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
// Collapse button // Layout buttons
if (!(flags & ImGuiWindowFlags_NoCollapse)) // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos, NULL)) float pad_l = style.FramePadding.x;
window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function float pad_r = style.FramePadding.x;
float button_sz = g.FontSize;
ImVec2 close_button_pos;
ImVec2 collapse_button_pos;
if (has_close_button)
{
pad_r += button_sz;
close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
}
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
{
pad_r += button_sz;
collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
}
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
{
collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
pad_l += button_sz;
}
// Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
if (has_collapse_button)
if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos, NULL))
window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
// Close button // Close button
if (p_open != NULL) if (has_close_button)
{ if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
const float rad = g.FontSize * 0.5f;
if (CloseButton(window->GetID("#CLOSE"), ImVec2(window->Pos.x + window->Size.x - style.FramePadding.x - rad, window->Pos.y + style.FramePadding.y + rad), rad + 1))
*p_open = false; *p_open = false;
}
window->DC.NavLayerCurrent = ImGuiNavLayer_Main; window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
@ -5466,23 +5493,32 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
// Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
// FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code.. // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code..
const char* UNSAVED_DOCUMENT_MARKER = "*"; const char* UNSAVED_DOCUMENT_MARKER = "*";
float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
ImRect text_r = title_bar_rect;
float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); // while uncentered title text will still reach edges correct.
if (style.WindowTitleAlign.x > 0.0f) if (pad_l > style.FramePadding.x)
pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x); pad_l += g.Style.ItemInnerSpacing.x;
text_r.Min.x += pad_left; if (pad_r > style.FramePadding.x)
text_r.Max.x -= pad_right; pad_r += g.Style.ItemInnerSpacing.x;
ImRect clip_rect = text_r; if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton() {
RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect); float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
pad_l = ImMax(pad_l, pad_extend * centerness);
pad_r = ImMax(pad_r, pad_extend * centerness);
}
ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y);
//if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
if (flags & ImGuiWindowFlags_UnsavedDocument) if (flags & ImGuiWindowFlags_UnsavedDocument)
{ {
ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f)); ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect); RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
} }
} }
@ -12479,8 +12515,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
PushItemFlag(ImGuiItemFlags_Disabled, true); PushItemFlag(ImGuiItemFlags_Disabled, true);
PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] * ImVec4(1.0f,1.0f,1.0f,0.5f)); PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] * ImVec4(1.0f,1.0f,1.0f,0.5f));
} }
const float rad = g.FontSize * 0.5f; const float button_sz = g.FontSize;
if (CloseButton(host_window->GetID("#CLOSE"), title_bar_rect.GetTR() + ImVec2(-style.FramePadding.x - rad, style.FramePadding.y + rad), rad + 1)) if (CloseButton(host_window->GetID("#CLOSE"), title_bar_rect.GetTR() + ImVec2(-style.FramePadding.x * 2.0f - button_sz, 0.0f)))
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->VisibleTabId)) if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->VisibleTabId))
{ {
node->WantCloseTabID = tab->ID; node->WantCloseTabID = tab->ID;

View File

@ -1354,6 +1354,7 @@ struct ImGuiStyle
float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints().
ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows.
float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding)

View File

@ -3078,6 +3078,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment"); ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
ImGui::Combo("WindowMenuButtonPosition", (int*)&style.WindowMenuButtonPosition, "Left\0Right\0");
ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
ImGui::Text("Safe Area Padding"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); ImGui::Text("Safe Area Padding"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");

View File

@ -869,7 +869,7 @@ struct ImGuiNextItemData
// Docking, Tabs // Docking, Tabs
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct ImGuiTabBarSortItem struct ImGuiShrinkWidthItem
{ {
int Index; int Index;
float Width; float Width;
@ -1115,7 +1115,7 @@ struct ImGuiContext
ImPool<ImGuiTabBar> TabBars; ImPool<ImGuiTabBar> TabBars;
ImGuiTabBar* CurrentTabBar; ImGuiTabBar* CurrentTabBar;
ImVector<ImGuiTabBarRef> CurrentTabBarStack; ImVector<ImGuiTabBarRef> CurrentTabBarStack;
ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer; ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer;
// Widget state // Widget state
ImVec2 LastValidMousePos; ImVec2 LastValidMousePos;
@ -1678,6 +1678,7 @@ namespace ImGui
IMGUI_API void PopItemFlag(); IMGUI_API void PopItemFlag();
IMGUI_API bool IsItemToggledSelection(); // was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) IMGUI_API bool IsItemToggledSelection(); // was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)
IMGUI_API ImVec2 GetWorkRectMax(); IMGUI_API ImVec2 GetWorkRectMax();
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
// Logging/Capture // Logging/Capture
IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name.
@ -1803,7 +1804,7 @@ namespace ImGui
// Widgets // Widgets
IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos);
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags);
IMGUI_API void Scrollbar(ImGuiAxis axis); IMGUI_API void Scrollbar(ImGuiAxis axis);

View File

@ -718,14 +718,14 @@ bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir)
} }
// Button to close a window // Button to close a window
bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius) bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)//, float size)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
// We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window. // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window.
// (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible).
const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius)); const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f);
bool is_clipped = !ItemAdd(bb, id); bool is_clipped = !ItemAdd(bb, id);
bool hovered, held; bool hovered, held;
@ -734,11 +734,12 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
return pressed; return pressed;
// Render // Render
ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
ImVec2 center = bb.GetCenter(); ImVec2 center = bb.GetCenter();
if (hovered) if (hovered)
window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9); window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12);
float cross_extent = (radius * 0.7071f) - 1.0f; float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;
ImU32 cross_col = GetColorU32(ImGuiCol_Text); ImU32 cross_col = GetColorU32(ImGuiCol_Text);
center -= ImVec2(0.5f, 0.5f); center -= ImVec2(0.5f, 0.5f);
window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f); window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f);
@ -758,11 +759,13 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
// Render
//bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed); //bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
ImVec2 off = dock_node ? ImVec2((float)(int)(-g.Style.ItemInnerSpacing.x * 0.5f) + 0.5f, 0.0f) : ImVec2(0.0f, 0.0f); ImVec2 off = dock_node ? ImVec2((float)(int)(-g.Style.ItemInnerSpacing.x * 0.5f) + 0.5f, 0.0f) : ImVec2(0.0f, 0.0f);
ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImVec2 center = bb.GetCenter();
if (hovered || held) if (hovered || held)
window->DrawList->AddCircleFilled(bb.GetCenter() + off + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, col, 9); window->DrawList->AddCircleFilled(center + off + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, col, 12);
if (dock_node) if (dock_node)
RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, GetColorU32(ImGuiCol_Text)); RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, GetColorU32(ImGuiCol_Text));
@ -1180,6 +1183,7 @@ void ImGui::Bullet()
// - SeparatorEx() [Internal] // - SeparatorEx() [Internal]
// - Separator() // - Separator()
// - SplitterBehavior() [Internal] // - SplitterBehavior() [Internal]
// - ShrinkWidths() [Internal]
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void ImGui::Spacing() void ImGui::Spacing()
@ -1361,6 +1365,33 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float
return held; return held;
} }
static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)
{
const ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs;
const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs;
if (int d = (int)(b->Width - a->Width))
return d;
return (b->Index - a->Index);
}
// Shrink excess width from a set of item, by removing width from the larger items first.
void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess)
{
if (count > 1)
ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);
int count_same_width = 1;
while (width_excess > 0.0f && count_same_width < count)
{
while (count_same_width < count && items[0].Width == items[count_same_width].Width)
count_same_width++;
float width_to_remove_per_item_max = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
float width_to_remove_per_item = ImMin(width_excess / count_same_width, width_to_remove_per_item_max);
for (int item_n = 0; item_n < count_same_width; item_n++)
items[item_n].Width -= width_to_remove_per_item;
width_excess -= width_to_remove_per_item * count_same_width;
}
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// [SECTION] Widgets: ComboBox // [SECTION] Widgets: ComboBox
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -2099,15 +2130,22 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
PushID(i); PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= DragScalar("", data_type, v, v_speed, v_min, v_max, format, power); value_changed |= DragScalar("", data_type, v, v_speed, v_min, v_max, format, power);
SameLine(0, g.Style.ItemInnerSpacing.x);
PopID(); PopID();
PopItemWidth(); PopItemWidth();
v = (void*)((char*)v + type_size); v = (void*)((char*)v + type_size);
} }
PopID(); PopID();
TextEx(label, FindRenderedTextEnd(label)); const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
{
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(label, label_end);
}
EndGroup(); EndGroup();
return value_changed; return value_changed;
} }
@ -2547,15 +2585,22 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
PushID(i); PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power); value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power);
SameLine(0, g.Style.ItemInnerSpacing.x);
PopID(); PopID();
PopItemWidth(); PopItemWidth();
v = (void*)((char*)v + type_size); v = (void*)((char*)v + type_size);
} }
PopID(); PopID();
TextEx(label, FindRenderedTextEnd(label)); const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
{
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(label, label_end);
}
EndGroup(); EndGroup();
return value_changed; return value_changed;
} }
@ -2858,8 +2903,13 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
value_changed = true; value_changed = true;
} }
SameLine(0, style.ItemInnerSpacing.x);
TextEx(label, FindRenderedTextEnd(label)); const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
{
SameLine(0, style.ItemInnerSpacing.x);
TextEx(label, label_end);
}
style.FramePadding = backup_frame_padding; style.FramePadding = backup_frame_padding;
PopID(); PopID();
@ -2891,15 +2941,22 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
for (int i = 0; i < components; i++) for (int i = 0; i < components; i++)
{ {
PushID(i); PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= InputScalar("", data_type, v, step, step_fast, format, flags); value_changed |= InputScalar("", data_type, v, step, step_fast, format, flags);
SameLine(0, g.Style.ItemInnerSpacing.x);
PopID(); PopID();
PopItemWidth(); PopItemWidth();
v = (void*)((char*)v + type_size); v = (void*)((char*)v + type_size);
} }
PopID(); PopID();
TextEx(label, FindRenderedTextEnd(label)); const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
{
SameLine(0.0f, g.Style.ItemInnerSpacing.x);
TextEx(label, label_end);
}
EndGroup(); EndGroup();
return value_changed; return value_changed;
} }
@ -5335,12 +5392,14 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags
bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label); bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label);
if (p_open) if (p_open)
{ {
// Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. // Create a small overlapping close button
// FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
// FIXME: CloseButton can overlap into text, need find a way to clip the text somehow.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiItemHoveredDataBackup last_item_backup; ImGuiItemHoveredDataBackup last_item_backup;
float button_radius = g.FontSize * 0.5f; float button_size = g.FontSize;
ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y); ImVec2 button_pos = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x * 2.0f - button_size, window->DC.LastItemRect.Min.y);
if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius)) if (CloseButton(window->GetID((void*)((intptr_t)id + 1)), button_pos))
*p_open = false; *p_open = false;
last_item_backup.Restore(); last_item_backup.Restore();
} }
@ -6231,15 +6290,6 @@ static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const voi
return (int)(a->Offset - b->Offset); return (int)(a->Offset - b->Offset);
} }
static int IMGUI_CDECL TabBarSortItemComparer(const void* lhs, const void* rhs)
{
const ImGuiTabBarSortItem* a = (const ImGuiTabBarSortItem*)lhs;
const ImGuiTabBarSortItem* b = (const ImGuiTabBarSortItem*)rhs;
if (int d = (int)(b->Width - a->Width))
return d;
return (b->Index - a->Index);
}
static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref) static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -6420,10 +6470,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x! if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x!
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
ImVector<ImGuiTabBarSortItem>& width_sort_buffer = g.TabSortByWidthBuffer;
width_sort_buffer.resize(tab_bar->Tabs.Size);
// Compute ideal widths // Compute ideal widths
g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size);
float width_total_contents = 0.0f; float width_total_contents = 0.0f;
ImGuiTabItem* most_recently_selected_tab = NULL; ImGuiTabItem* most_recently_selected_tab = NULL;
bool found_selected_tab_id = false; bool found_selected_tab_id = false;
@ -6447,8 +6495,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents;
// Store data so we can build an array sorted by width if we need to shrink tabs down // Store data so we can build an array sorted by width if we need to shrink tabs down
width_sort_buffer[tab_n].Index = tab_n; g.ShrinkWidthBuffer[tab_n].Index = tab_n;
width_sort_buffer[tab_n].Width = tab->WidthContents; g.ShrinkWidthBuffer[tab_n].Width = tab->WidthContents;
} }
// Compute width // Compute width
@ -6457,21 +6505,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown))
{ {
// If we don't have enough room, resize down the largest tabs first // If we don't have enough room, resize down the largest tabs first
if (tab_bar->Tabs.Size > 1) ShrinkWidths(g.ShrinkWidthBuffer.Data, g.ShrinkWidthBuffer.Size, width_excess);
ImQsort(width_sort_buffer.Data, (size_t)width_sort_buffer.Size, sizeof(ImGuiTabBarSortItem), TabBarSortItemComparer);
int tab_count_same_width = 1;
while (width_excess > 0.0f && tab_count_same_width < tab_bar->Tabs.Size)
{
while (tab_count_same_width < tab_bar->Tabs.Size && width_sort_buffer[0].Width == width_sort_buffer[tab_count_same_width].Width)
tab_count_same_width++;
float width_to_remove_per_tab_max = (tab_count_same_width < tab_bar->Tabs.Size) ? (width_sort_buffer[0].Width - width_sort_buffer[tab_count_same_width].Width) : (width_sort_buffer[0].Width - 1.0f);
float width_to_remove_per_tab = ImMin(width_excess / tab_count_same_width, width_to_remove_per_tab_max);
for (int tab_n = 0; tab_n < tab_count_same_width; tab_n++)
width_sort_buffer[tab_n].Width -= width_to_remove_per_tab;
width_excess -= width_to_remove_per_tab * tab_count_same_width;
}
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
tab_bar->Tabs[width_sort_buffer[tab_n].Index].Width = (float)(int)width_sort_buffer[tab_n].Width; tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = (float)(int)g.ShrinkWidthBuffer[tab_n].Width;
} }
else else
{ {
@ -7151,16 +7187,18 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
if (close_button_visible) if (close_button_visible)
{ {
ImGuiItemHoveredDataBackup last_item_backup; ImGuiItemHoveredDataBackup last_item_backup;
const float close_button_sz = g.FontSize * 0.5f; const float close_button_sz = g.FontSize;
if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x - close_button_sz, bb.Min.y + frame_padding.y + close_button_sz), close_button_sz)) PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding);
if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x * 2.0f - close_button_sz, bb.Min.y)))
close_button_pressed = true; close_button_pressed = true;
PopStyleVar();
last_item_backup.Restore(); last_item_backup.Restore();
// Close with middle mouse button // Close with middle mouse button
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
close_button_pressed = true; close_button_pressed = true;
text_pixel_clip_bb.Max.x -= close_button_sz * 2.0f; text_pixel_clip_bb.Max.x -= close_button_sz;
} }
// Label with ellipsis // Label with ellipsis