diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bfcc6820..5d37b85f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,15 +45,6 @@ HOW TO UPDATE? - Added io.ConfigDockingWithShift option to configure docking mode. - Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingEmptyBg colors. - Demo: Added "DockSpace" example app showcasing use of explicit dockspace nodes. -- Added Tab Bar/Tabs widgets: (#261, #351) - - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. - - Added ImGuiTabBarFlags flags for BeginTabBar(). - - Added ImGuiTabItemFlags flags for BeginTabItem(). - - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. - - Demo: Added Layout->Tabs demo code. - - Demo: Added "Documents" example app showcasing possible use for tabs. -- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering - the ID, as a convenience to avoid using the ### operator. ----------------------------------------------------------------------- @@ -66,6 +57,17 @@ Breaking Changes: The addition of new configuration options in the Docking branch is pushing for a little reorganization of those names. Other Changes: +- Added BETA api for Tab Bar/Tabs widgets: (#261, #351) + - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. + - Added ImGuiTabBarFlags flags for BeginTabBar(). + - Added ImGuiTabItemFlags flags for BeginTabItem(). + - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. + - Demo: Added Layout->Tabs demo code. + - Demo: Added "Documents" example app showcasing possible use for tabs. + This feature was merged from the Docking branch in order to allow the use of regular tabs in your code. + (It does not provide the docking/splitting/merging of windows available in the Docking branch) +- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering + the ID, as a convenience to avoid using the ### operator. - Resizing windows from edge is now enabled by default (io.ConfigWindowsResizeFromEdges=true). Note that it only works _if_ the back-end sets ImGuiBackendFlags_HasMouseCursors, which the standard back-end do. - Added io.ConfigWindowsMoveFromTitleBarOnly option. Still is ignored by window with no title bars (often popups). diff --git a/imgui.cpp b/imgui.cpp index e3456a0a..00f43d7b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2368,7 +2368,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) Name = ImStrdup(name); ID = ImHash(name, 0); IDStack.push_back(ID); - Flags = FlagsPreviousFrame = 0; + Flags = FlagsPreviousFrame = ImGuiWindowFlags_None; Viewport = NULL; ViewportId = 0; ViewportAllowPlatformMonitorExtend = -1; @@ -2677,7 +2677,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemId = id; window->DC.LastItemRect = bb; - window->DC.LastItemStatusFlags = 0; + window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE ImGuiTestEngineHook_ItemAdd(id, bb); @@ -8691,7 +8691,7 @@ static void ImGui::NavUpdate() if (g.NavMoveRequestForward == ImGuiNavForward_None) { g.NavMoveDir = ImGuiDir_None; - g.NavMoveRequestFlags = 0; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { if ((allowed_dir_flags & (1<TabBar = IM_NEW(ImGuiTabBar)(); for (int n = 0; n < target_node->Windows.Size; n++) - TabBarAddTab(target_node->TabBar, target_node->Windows[n], ImGuiTabItemFlags_None); + TabBarAddTab(target_node->TabBar, ImGuiTabItemFlags_None, target_node->Windows[n]); } if (payload_node != NULL) @@ -10477,9 +10477,9 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b // Add existing windows for (int n = 0; n < node->Windows.Size - 1; n++) - TabBarAddTab(node->TabBar, node->Windows[n], ImGuiTabItemFlags_None); + TabBarAddTab(node->TabBar, ImGuiTabItemFlags_None, node->Windows[n]); } - TabBarAddTab(node->TabBar, window, ImGuiTabItemFlags_Unsorted); + TabBarAddTab(node->TabBar, ImGuiTabItemFlags_Unsorted, window); } DockNodeUpdateVisibleFlag(node); @@ -11089,7 +11089,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w if (g.NavWindow && g.NavWindow->RootWindowDockStop == window) tab_bar->SelectedTabId = window->ID; if (TabBarFindTabByID(tab_bar, window->ID) == NULL) - TabBarAddTab(tab_bar, window, ImGuiTabItemFlags_Unsorted); + TabBarAddTab(tab_bar, ImGuiTabItemFlags_Unsorted, window); } // If multiple tabs are appearing on the same frame, sort them based on their persistent DockOrder value @@ -13466,7 +13466,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImGui::TreePop(); } - if (ImGui::TreeNode("Docking & Tabs")) + if (ImGui::TreeNode("Docking & Tab Bars")) { ShowDockingDebug(); ImGui::TreePop(); @@ -13546,9 +13546,10 @@ void ImGui::ShowDockingDebug() ImGui::TreePop(); } } + static void NodeTabBar(ImGuiTabBar* tab_bar) { - // Previous window list + // Note that standalone tab bars (not associated to docking/windows functionality) currently hold no discernable strings. char buf[256]; char* p = buf; const char* buf_end = buf + IM_ARRAYSIZE(buf); diff --git a/imgui.h b/imgui.h index 15085c7d..d772c8c5 100644 --- a/imgui.h +++ b/imgui.h @@ -544,7 +544,8 @@ namespace ImGui IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column IMGUI_API int GetColumnsCount(); - // Tabs + // Tab Bars, Tabs + // [BETA API] API may evolve! // Note: Tabs are automatically created by the docking system. Use this to create tab bars/tabs yourself without docking being involved. IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar IMGUI_API void EndTabBar(); @@ -573,7 +574,7 @@ namespace ImGui IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) // Drag and Drop - // [BETA API] Missing Demo code. API may evolve. + // [BETA API] Missing Demo code. API may evolve! IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t size, ImGuiCond cond = 0);// type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 41750b14..b21b0768 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4068,7 +4068,7 @@ struct ExampleAppDocuments } }; -// [Optional] Notify the system of Tabs/Windows of closure that happened outside the regular tab interface +// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed // to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence. // During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b873b3f8..098c89af 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -206,10 +206,10 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); @@ -263,10 +263,10 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); @@ -321,10 +321,10 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); @@ -2990,8 +2990,9 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight); } -// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem... can't rely on font glyph having it, and regular dot are typically too wide. -// If we render a dot/shape ourselves it comes with the risk that it wouldn't match the boldness or positioning of what the font uses... +// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it, +// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match +// the boldness or positioning of what the font uses... void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col) { pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); diff --git a/imgui_internal.h b/imgui_internal.h index 4dfc42e3..a91565a4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1334,17 +1334,17 @@ struct ImGuiItemHoveredDataBackup enum ImGuiTabBarFlagsPrivate_ { - ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node - ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // Part of an explicit dockspace node node - ImGuiTabBarFlags_IsFocused = 1 << 22, - ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs + ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node + ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // Part of an explicit dockspace node node + ImGuiTabBarFlags_IsFocused = 1 << 22, + ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs }; enum ImGuiTabItemFlagsPrivate_ { - ImGuiTabItemFlags_DockedWindow = 1 << 20, // [Docking] - ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. - ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) + ImGuiTabItemFlags_DockedWindow = 1 << 20, // [Docking] + ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. + ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) }; // Storage for one active tab item (sizeof() 32~40 bytes) @@ -1352,14 +1352,14 @@ struct ImGuiTabItem { ImGuiID ID; ImGuiTabItemFlags Flags; - ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window. + ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window. int LastFrameVisible; - int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance - float Offset; // Position relative to beginning of tab - float Width; // Width currently displayed - float WidthContents; // Width of actual contents, stored during BeginTabItem() call + int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + float Offset; // Position relative to beginning of tab + float Width; // Width currently displayed + float WidthContents; // Width of actual contents, stored during BeginTabItem() call - ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; } + ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; } }; // Storage for a tab bar (sizeof() 92~96 bytes) @@ -1548,7 +1548,7 @@ namespace ImGui // Tab Bars IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node); IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); - IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window, ImGuiTabItemFlags tab_flags = ImGuiTabItemFlags_None); + IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window); IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f1bf3641..11a1fb7e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5790,6 +5790,8 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, //------------------------------------------------------------------------- // [SECTION] Widgets: BeginTabBar, EndTabBar, etc. //------------------------------------------------------------------------- +// [BETA API] API may evolve! +//------------------------------------------------------------------------- // - BeginTabBar() // - BeginTabBarEx() [Internal] // - EndTabBar() @@ -5980,7 +5982,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) { if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId)) { - IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size) { @@ -6142,7 +6144,7 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) // The purpose of this call is to register tab in advance so we can control their order at the time they appear. // Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function. -void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window, ImGuiTabItemFlags tab_flags) +void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window) { ImGuiContext& g = *GImGui; IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL); @@ -6306,6 +6308,8 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) //------------------------------------------------------------------------- // [SECTION] Widgets: BeginTabItem, EndTabItem, etc. //------------------------------------------------------------------------- +// [BETA API] API may evolve! +//------------------------------------------------------------------------- // - BeginTabItem() // - EndTabItem() // - TabItemEx() [Internal] @@ -6472,8 +6476,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, } else if (held && !tab_appearing && IsMouseDragging(0)) { - // Drag and drop - // Re-order local or dockable tabs + // Drag and drop: re-order tabs float drag_distance_from_edge_x = 0.0f; if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (flags & ImGuiTabItemFlags_DockedWindow))) { @@ -6628,7 +6631,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI draw_list->PathClear(); } -// Render text label (with clipping + alpha gradient) + unsaved marker + Close Button logic +// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id) { ImGuiContext& g = *GImGui; @@ -6674,7 +6677,7 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, } // Label with ellipsis - // FIXME: This could be extracted into a helper but or use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment + // FIXME: This should be extracted into a helper but the use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment const char* label_display_end = FindRenderedTextEnd(label); if (label_size.x > text_ellipsis_clip_bb.GetWidth()) {