Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions ThemeProvider.ImGui/ImGuiPaletteMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ public IReadOnlyDictionary<ImGuiCol, Vector4> 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
Expand Down
24 changes: 24 additions & 0 deletions ThemeProvider.Test/ImGuiPaletteMapperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,30 @@ public void MapTheme_AlternateRowDiffersFromFrame()
}
}

/// <summary>
/// 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.
/// </summary>
[TestMethod]
public void MapTheme_SelectedTabsDifferFromTheirTabBar()
{
ImGuiPaletteMapper mapper = new();

foreach (ThemeRegistry.ThemeInfo info in ThemeRegistry.AllThemes)
{
IReadOnlyDictionary<ImGuiCol, Vector4> 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<ImGuiCol, Vector4> 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<SemanticMeaning, Collection<Color>> SemanticMapping { get; } = new()
Expand Down
Loading