diff --git a/ThemeProvider.ImGui/ImGuiPaletteMapper.cs b/ThemeProvider.ImGui/ImGuiPaletteMapper.cs index 60417ad..8f51942 100644 --- a/ThemeProvider.ImGui/ImGuiPaletteMapper.cs +++ b/ThemeProvider.ImGui/ImGuiPaletteMapper.cs @@ -87,12 +87,14 @@ public IReadOnlyDictionary MapTheme(ISemanticTheme theme) { ImGuiCol.TreeLines, new(SemanticMeaning.Neutral, Priority.MediumHigh)}, { ImGuiCol.Tab, new(SemanticMeaning.Neutral, Priority.Low)}, - { ImGuiCol.TabSelected, new(SemanticMeaning.Primary, Priority.VeryLow)}, - { ImGuiCol.TabHovered, new(SemanticMeaning.Primary, Priority.Low)}, + // The tab bar is filled with the title bar's color, so the selected tab sits one step above it + // to read as the open tab, and hovering steps up once more. + { ImGuiCol.TabSelected, new(SemanticMeaning.Primary, Priority.Low)}, + { ImGuiCol.TabHovered, new(SemanticMeaning.Primary, Priority.MediumLow)}, { ImGuiCol.TabSelectedOverline, new(SemanticMeaning.Primary, Priority.High)}, // Tabs in an unfocused window drop to neutral so the focused window's tabs stand out. { ImGuiCol.TabDimmed, new(SemanticMeaning.Neutral, Priority.VeryLow)}, - { ImGuiCol.TabDimmedSelected, new(SemanticMeaning.Neutral, Priority.Low)}, + { ImGuiCol.TabDimmedSelected, new(SemanticMeaning.Neutral, Priority.MediumLow)}, { ImGuiCol.TabDimmedSelectedOverline, new(SemanticMeaning.Primary, Priority.High)}, // Alternate elements spread across the full 20-82% non-neutral range for better contrast diff --git a/ThemeProvider.Test/ImGuiPaletteMapperTests.cs b/ThemeProvider.Test/ImGuiPaletteMapperTests.cs index 67d4dbe..c98873b 100644 --- a/ThemeProvider.Test/ImGuiPaletteMapperTests.cs +++ b/ThemeProvider.Test/ImGuiPaletteMapperTests.cs @@ -233,6 +233,30 @@ public void MapTheme_AlternateRowDiffersFromFrame() } } + /// + /// ImGui fills a dock node's tab bar with TitleBgActive when focused and TitleBg otherwise, and draws + /// the selected tab with TabSelected or TabDimmedSelected. Each selected tab must differ from the bar + /// it sits on, or only the 1px overline shows which tab is open. Hovering must also read differently + /// from being selected. + /// + [TestMethod] + public void MapTheme_SelectedTabsDifferFromTheirTabBar() + { + ImGuiPaletteMapper mapper = new(); + + foreach (ThemeRegistry.ThemeInfo info in ThemeRegistry.AllThemes) + { + IReadOnlyDictionary palette = mapper.MapTheme(info.CreateInstance()); + + AssertDistinct(palette, ImGuiCol.TabSelected, ImGuiCol.TitleBgActive, info.Name); + AssertDistinct(palette, ImGuiCol.TabDimmedSelected, ImGuiCol.TitleBg, info.Name); + AssertDistinct(palette, ImGuiCol.TabHovered, ImGuiCol.TabSelected, info.Name); + } + } + + private static void AssertDistinct(IReadOnlyDictionary palette, ImGuiCol first, ImGuiCol second, string themeName) => + Assert.IsGreaterThan(1f / 255f, Vector4.Distance(palette[first], palette[second]), $"{themeName}: {first} is drawn in the {second} color"); + private sealed class NoNeutralTheme : ISemanticTheme { public Dictionary> SemanticMapping { get; } = new()