Skip to content
Closed
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
15 changes: 2 additions & 13 deletions src/ui/Features/Main/Layout/InitListViewAndEditBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,8 @@ internal static Grid MakeLayoutListViewAndEditBox(MainView mainPage, MainViewMod
if (Se.Settings.Appearance.GridAlternatingRows)
{
var isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark;
var altColorHex = UiTheme.GetGridAlternatingRowColorHex(isDark);
try
{
if (!string.IsNullOrWhiteSpace(altColorHex))
{
alternatingRowBrush = new SolidColorBrush(altColorHex.FromHexToColor());
vm.SubtitleGridAlternatingRowBrush = alternatingRowBrush;
}
}
catch
{
alternatingRowBrush = null;
}
alternatingRowBrush = new SolidColorBrush(UiTheme.GetGridAlternatingRowColor(isDark));
vm.SubtitleGridAlternatingRowBrush = alternatingRowBrush;
}

// Collapse hidden rows (style bindings evaluate against the row's item).
Expand Down
10 changes: 1 addition & 9 deletions src/ui/Features/Main/MainViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15534,15 +15534,7 @@ private void UpdateAlternatingRowBrush()
// Color notifies every realized row without rebuilding the grid (and losing its state).
if (SubtitleGridAlternatingRowBrush != null)
{
var colorHex = UiTheme.GetGridAlternatingRowColorHex(Application.Current?.ActualThemeVariant == ThemeVariant.Dark);
try
{
SubtitleGridAlternatingRowBrush.Color = colorHex.FromHexToColor();
}
catch
{
// Keep the current brush color when the configured value is invalid.
}
SubtitleGridAlternatingRowBrush.Color = UiTheme.GetGridAlternatingRowColor(Application.Current?.ActualThemeVariant == ThemeVariant.Dark);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/ui/Features/Options/Settings/SettingsPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,8 +1144,8 @@ private List<SettingsSection> CreateSections()
MakeCheckboxSetting(Se.Language.Options.Settings.ShowTimeCodeModeInStatusBar, nameof(_vm.ShowTimeCodeModeInStatusBar)),
MakeCheckboxSetting(Se.Language.Options.Settings.GridCompactMode, nameof(_vm.GridCompactMode)),
MakeCheckboxSetting(Se.Language.Options.Settings.GridAlternatingRows, nameof(_vm.GridAlternatingRows)),
new SettingsItem(Se.Language.Options.Settings.GridAlternatingRowColor, () => UiUtil.MakeColorPickerButton(_vm, nameof(_vm.GridAlternatingRowColor))),
new SettingsItem(Se.Language.Options.Settings.GridAlternatingRowColorDark, () => UiUtil.MakeColorPickerButton(_vm, nameof(_vm.GridAlternatingRowColorDark))),
MakeNumericSettingInt(Se.Language.Options.Settings.GridAlternatingRowContrast, nameof(_vm.GridAlternatingRowContrast),
UiTheme.MinGridAlternatingRowContrast, UiTheme.MaxGridAlternatingRowContrast),
new SettingsItem(Se.Language.Options.Settings.ShowGridLines, () => UiUtil.MakeComboBox(_vm.GridLinesVisibilities, _vm, nameof(_vm.SelectedGridLinesVisibility))),
new SettingsItem(Se.Language.Options.Settings.BookmarkColor, () => UiUtil.MakeColorPickerButton(_vm, nameof(_vm.BookmarkColor))),
new SettingsItem(Se.Language.Options.Settings.SpellCheckHighlightColor, () => UiUtil.MakeColorPickerButton(_vm, nameof(_vm.SpellCheckHighlightColor))),
Expand Down
9 changes: 3 additions & 6 deletions src/ui/Features/Options/Settings/SettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,7 @@ private static int ParseMouseWheelStep(string display)
[ObservableProperty] private Color _focusedButtonBackgroundColor;
[ObservableProperty] private Color _bookmarkColor;
[ObservableProperty] private Color _spellCheckHighlightColor;
[ObservableProperty] private Color _gridAlternatingRowColor;
[ObservableProperty] private Color _gridAlternatingRowColorDark;
[ObservableProperty] private int _gridAlternatingRowContrast;
[ObservableProperty] private bool _isEditCustomContinuationStyleVisible;
[ObservableProperty] private bool _isMpvChosen;

Expand Down Expand Up @@ -1057,8 +1056,7 @@ private void LoadSettings()
FocusedButtonBackgroundColor = appearance.FocusedButtonBackgroundColor.FromHexToColor();
BookmarkColor = appearance.BookmarkColor.FromHexToColor();
SpellCheckHighlightColor = appearance.SpellCheckHighlightColor.FromHexToColor();
GridAlternatingRowColor = appearance.GridAlternatingRowColor.FromHexToColor();
GridAlternatingRowColorDark = appearance.GridAlternatingRowColorDark.FromHexToColor();
GridAlternatingRowContrast = UiTheme.ClampGridAlternatingRowContrast(appearance.GridAlternatingRowContrast);
ShowUpDownStartTime = appearance.ShowUpDownStartTime;
ShowTimeCodeModeInStatusBar = appearance.ShowTimeCodeModeInStatusBar;
ShowUpDownEndTime = appearance.ShowUpDownEndTime;
Expand Down Expand Up @@ -1972,8 +1970,7 @@ private void SaveSettings()
appearance.FocusedButtonBackgroundColor = FocusedButtonBackgroundColor.FromColorToHex();
appearance.BookmarkColor = BookmarkColor.FromColorToHex();
appearance.SpellCheckHighlightColor = SpellCheckHighlightColor.FromColorToHex();
appearance.GridAlternatingRowColor = GridAlternatingRowColor.FromColorToHex();
appearance.GridAlternatingRowColorDark = GridAlternatingRowColorDark.FromColorToHex();
appearance.GridAlternatingRowContrast = UiTheme.ClampGridAlternatingRowContrast(GridAlternatingRowContrast);
appearance.ShowUpDownStartTime = ShowUpDownStartTime;
appearance.ShowTimeCodeModeInStatusBar = ShowTimeCodeModeInStatusBar;
appearance.ShowUpDownEndTime = ShowUpDownEndTime;
Expand Down
6 changes: 2 additions & 4 deletions src/ui/Logic/Config/Language/Options/LanguageSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ public class LanguageSettings
public string ShowTimeCodeModeInStatusBar { get; set; }
public string GridCompactMode { get; set; }
public string GridAlternatingRows { get; set; }
public string GridAlternatingRowColor { get; set; }
public string GridAlternatingRowColorDark { get; set; }
public string GridAlternatingRowContrast { get; set; }
public string UiFont { get; set; }
public string IconTheme { get; set; }
public string DarkThemeForegroundColor { get; set; }
Expand Down Expand Up @@ -462,8 +461,7 @@ public LanguageSettings()
ShowTimeCodeModeInStatusBar = "Show time code mode in status bar";
GridCompactMode = "Use compact mode for grids";
GridAlternatingRows = "Use alternating row colors in grid";
GridAlternatingRowColor = "Alternating row color (light theme)";
GridAlternatingRowColorDark = "Alternating row color (dark theme)";
GridAlternatingRowContrast = "Alternating row contrast (%)";
UiFont = "UI font";
IconTheme = "Icon theme";
DarkThemeForegroundColor = "Dark theme foreground color";
Expand Down
6 changes: 2 additions & 4 deletions src/ui/Logic/Config/SeAppearance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ public class SeAppearance
/// </summary>
public string WindowsRenderingMode { get; set; }
public bool GridAlternatingRows { get; set; }
public string GridAlternatingRowColor { get; set; }
public string GridAlternatingRowColorDark { get; set; }
public int GridAlternatingRowContrast { get; set; }
public bool ShowHorizontalLineAboveToolbar { get; set; }

/// <summary>
Expand Down Expand Up @@ -150,8 +149,7 @@ public SeAppearance()
GridLinesAppearance = SeGridLinesVisibility.None.ToString();
WindowsRenderingMode = nameof(WindowsRenderingModeType.Default);
GridAlternatingRows = true;
GridAlternatingRowColor = new Color(255, 245, 245, 245).FromColorToHex();
GridAlternatingRowColorDark = new Color(255, 45, 45, 45).FromColorToHex();
GridAlternatingRowContrast = 10;
DarkModeBackgroundColor = new Color(255, 33, 33, 33).FromColorToHex();
DarkModeForegroundColor = new Color(255, 220, 220, 220).FromColorToHex();
UseFocusedButtonBackgroundColor = true;
Expand Down
53 changes: 35 additions & 18 deletions src/ui/Logic/UiTheme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1837,39 +1837,53 @@ internal static Color GetLightThemeBackgroundColor(string? themeSetting)
private static readonly Color PastelBackgroundColor = Color.FromRgb(240, 235, 255);
internal static readonly Color NordBackgroundColor = Color.FromRgb(0x2E, 0x34, 0x40); // nord0
internal static readonly Color NordForegroundColor = Color.FromRgb(0xE5, 0xE9, 0xF0); // nord5
private static readonly Color NordAlternatingRowColor = Color.FromRgb(0x34, 0x3B, 0x48);
internal static readonly Color MidnightCinemaBackgroundColor = Color.FromRgb(0x14, 0x12, 0x18);
internal static readonly Color MidnightCinemaForegroundColor = Color.FromRgb(0xEC, 0xE6, 0xD9);
internal static readonly Color MidnightCinemaHeaderColor = Color.FromRgb(0x1E, 0x1B, 0x24);
internal static readonly Color MidnightCinemaAccentColor = Color.FromRgb(0xE8, 0xA3, 0x3D);
private static readonly Color MidnightCinemaAlternatingRowColor = Color.FromRgb(0x1A, 0x17, 0x20);
internal static readonly Color SakuraBackgroundColor = Color.FromRgb(0xFF, 0xF7, 0xF9);
internal static readonly Color SakuraForegroundColor = Color.FromRgb(0x3A, 0x2A, 0x31);
internal static readonly Color SakuraAccentColor = Color.FromRgb(0xD9, 0x46, 0x6F);
private static readonly Color SakuraAlternatingRowColor = Color.FromRgb(0xFD, 0xEF, 0xF3);

public const int MinGridAlternatingRowContrast = 4;
public const int MaxGridAlternatingRowContrast = 20;

public static int ClampGridAlternatingRowContrast(int percent) =>
Math.Clamp(percent, MinGridAlternatingRowContrast, MaxGridAlternatingRowContrast);

/// <summary>
/// The subtitle grid's alternating row color. The fixed-palette themes have their own - the
/// gray settings read as stray gray stripes on their tinted rows.
/// The subtitle grid's alternating row color: the theme background moved the configured
/// percentage toward the theme text color. Following both colors keeps the stripe in the
/// theme's own tint (Sakura pink, Nord blue-gray) and makes it darker on light themes and
/// lighter on dark ones without a light/dark color pair to keep in step (#16779).
/// </summary>
public static string GetGridAlternatingRowColorHex(bool isDark)
public static Color GetGridAlternatingRowColor(bool isDark)
{
var theme = Se.Settings.Appearance.Theme;
if (!isDark)
Color background;
Color foreground;
try
{
return theme == ThemeNameSakura
? SakuraAlternatingRowColor.FromColorToHex()
: Se.Settings.Appearance.GridAlternatingRowColor;
background = isDark ? GetDarkThemeBackgroundColor() : GetLightThemeBackgroundColor(Se.Settings.Appearance.Theme);
foreground = isDark ? GetDarkThemeForegroundColor() : GetLightThemeForegroundColor(Se.Settings.Appearance.Theme);
}

if (theme == ThemeNameNord)
catch
{
return NordAlternatingRowColor.FromColorToHex();
// malformed dark-mode colors in the settings file
background = isDark ? Color.FromRgb(0x21, 0x21, 0x21) : Colors.White;
foreground = isDark ? Color.FromRgb(0xDC, 0xDC, 0xDC) : Colors.Black;
}

return theme == ThemeNameMidnightCinema
? MidnightCinemaAlternatingRowColor.FromColorToHex()
: Se.Settings.Appearance.GridAlternatingRowColorDark;
return BlendGridAlternatingRowColor(background, foreground, Se.Settings.Appearance.GridAlternatingRowContrast);
}

internal static Color BlendGridAlternatingRowColor(Color background, Color foreground, int percent)
{
var amount = ClampGridAlternatingRowContrast(percent) / 100.0;
static byte Mix(byte from, byte to, double t) => (byte)Math.Round(from + (to - from) * t);
return Color.FromRgb(
Mix(background.R, foreground.R, amount),
Mix(background.G, foreground.G, amount),
Mix(background.B, foreground.B, amount));
}

private static readonly WaveformColors MidnightCinemaWaveformColors = new(
Expand Down Expand Up @@ -1996,9 +2010,12 @@ public static Color GetThemeForegroundColor()
return GetDarkThemeForegroundColor();
}

return ThemeName == ThemeNameSakura ? SakuraForegroundColor : Colors.Black;
return GetLightThemeForegroundColor(ThemeName);
}

internal static Color GetLightThemeForegroundColor(string? themeSetting) =>
themeSetting == ThemeNameSakura ? SakuraForegroundColor : Colors.Black;

public static Color GetDarkThemeForegroundColor()
{
var theme = Se.Settings.Appearance.Theme;
Expand Down
53 changes: 53 additions & 0 deletions tests/UI/Logic/GridAlternatingRowContrastTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Avalonia.Media;
using Nikse.SubtitleEdit.Logic;
using Nikse.SubtitleEdit.Logic.Config;

namespace UITests.Logic;

/// <summary>
/// The grid's alternating row tint is the theme background moved a percentage (4-20%) toward
/// the theme text color, so it is visible on every theme without hand-picked colors (#16779).
/// </summary>
public class GridAlternatingRowContrastTests
{
[Fact]
public void Light_Theme_Darkens_White_By_The_Percentage()
{
var color = UiTheme.BlendGridAlternatingRowColor(Colors.White, Colors.Black, 10);

Assert.Equal(Color.FromRgb(230, 230, 230), color);
}

[Fact]
public void Dark_Theme_Lightens_Toward_Foreground()
{
var background = Color.FromRgb(33, 33, 33);
var foreground = Color.FromRgb(220, 220, 220);

var color = UiTheme.BlendGridAlternatingRowColor(background, foreground, 20);

Assert.True(color.R > background.R);
Assert.Equal(Color.FromRgb(70, 70, 70), color);
}

[Theory]
[InlineData(0, 4)]
[InlineData(4, 4)]
[InlineData(12, 12)]
[InlineData(20, 20)]
[InlineData(99, 20)]
public void Percentage_Is_Clamped(int value, int expected)
{
Assert.Equal(expected, UiTheme.ClampGridAlternatingRowContrast(value));
}

[Fact]
public void Default_Is_Visible_On_Light_Theme()
{
Assert.Equal(10, new SeAppearance().GridAlternatingRowContrast);
var color = UiTheme.BlendGridAlternatingRowColor(Colors.White, Colors.Black, 10);

// The old default was #F5F5F5, too faint to notice on many screens.
Assert.Equal(Color.FromRgb(230, 230, 230), color);
}
}
Loading