diff --git a/src/LogExpert.Core/Config/Preferences.cs b/src/LogExpert.Core/Config/Preferences.cs
index ff4dd1bd..8e70cc8a 100644
--- a/src/LogExpert.Core/Config/Preferences.cs
+++ b/src/LogExpert.Core/Config/Preferences.cs
@@ -10,6 +10,14 @@ namespace LogExpert.Core.Config;
[Serializable]
public class Preferences
{
+ private SelectionHighlightSettings _selectionHighlight = new();
+
+ public SelectionHighlightSettings SelectionHighlight
+ {
+ get => _selectionHighlight;
+ set => _selectionHighlight = value ?? new();
+ }
+
///
/// List of highlight groups for syntax highlighting and text coloring.
///
@@ -236,4 +244,4 @@ public Font Font
public float FontSize { get => field; set => field = MathF.Round(value, 1); } = 9.0f;
public List HighlightMaskList { get; set; } = [];
-}
\ No newline at end of file
+}
diff --git a/src/LogExpert.Core/Config/SelectionHighlightSettings.cs b/src/LogExpert.Core/Config/SelectionHighlightSettings.cs
new file mode 100644
index 00000000..0f86cae7
--- /dev/null
+++ b/src/LogExpert.Core/Config/SelectionHighlightSettings.cs
@@ -0,0 +1,13 @@
+using System.Drawing;
+
+namespace LogExpert.Core.Config;
+
+/// Application-wide selection appearance, edited in the Highlights dialog.
+[Serializable]
+public sealed class SelectionHighlightSettings
+{
+ public bool Outline { get; set; }
+
+ /// Null follows the system selection color.
+ public Color? CustomColor { get; set; }
+}
\ No newline at end of file
diff --git a/src/LogExpert.Resources/Resources.Designer.cs b/src/LogExpert.Resources/Resources.Designer.cs
index 22218342..8ddf47dd 100644
--- a/src/LogExpert.Resources/Resources.Designer.cs
+++ b/src/LogExpert.Resources/Resources.Designer.cs
@@ -23,6 +23,21 @@ namespace LogExpert {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
+ public static string HighlightDialog_UI_SelectionHighlight {
+ get { return ResourceManager.GetString("HighlightDialog_UI_SelectionHighlight", resourceCulture); }
+ }
+
+ public static string HighlightDialog_UI_OutlineSelectedBlocks {
+ get { return ResourceManager.GetString("HighlightDialog_UI_OutlineSelectedBlocks", resourceCulture); }
+ }
+
+ public static string HighlightDialog_UI_ChangeSelectionColor {
+ get { return ResourceManager.GetString("HighlightDialog_UI_ChangeSelectionColor", resourceCulture); }
+ }
+
+ public static string HighlightDialog_UI_ResetSelectionColor {
+ get { return ResourceManager.GetString("HighlightDialog_UI_ResetSelectionColor", resourceCulture); }
+ }
private static global::System.Resources.ResourceManager resourceMan;
diff --git a/src/LogExpert.Resources/Resources.de.resx b/src/LogExpert.Resources/Resources.de.resx
index a83dac05..c4707f6e 100644
--- a/src/LogExpert.Resources/Resources.de.resx
+++ b/src/LogExpert.Resources/Resources.de.resx
@@ -2231,4 +2231,16 @@ LogExpert neu starten, um die Änderungen zu übernehmen?
Sysout für das Tool wurde konfiguriert, aber es gibt keine aktive Logdatei. Das Tool wird ohne die Sysout-Pipe gestartet
-
\ No newline at end of file
+
+ Auswahlhervorhebung (alle Gruppen)
+
+
+ Ausgewählte Blöcke umranden
+
+
+ Farbe der Auswahlhervorhebung ändern...
+
+
+ Systemfarbe verwenden
+
+
diff --git a/src/LogExpert.Resources/Resources.resx b/src/LogExpert.Resources/Resources.resx
index 22abd07a..3b0349b2 100644
--- a/src/LogExpert.Resources/Resources.resx
+++ b/src/LogExpert.Resources/Resources.resx
@@ -2265,4 +2265,16 @@ Restart LogExpert to apply changes?
Sysout for the Tool was configured, but there is no active logfile the Tool will be started without the Sysout Pipe
-
\ No newline at end of file
+
+ Selection highlight (all groups)
+
+
+ Outline selected blocks
+
+
+ Change selection highlight color...
+
+
+ Use system color
+
+
diff --git a/src/LogExpert.Tests/ConfigManagerTests/SelectionHighlightSettingsTests.cs b/src/LogExpert.Tests/ConfigManagerTests/SelectionHighlightSettingsTests.cs
new file mode 100644
index 00000000..4b4b0bf4
--- /dev/null
+++ b/src/LogExpert.Tests/ConfigManagerTests/SelectionHighlightSettingsTests.cs
@@ -0,0 +1,34 @@
+using LogExpert.Core.Config;
+
+using Newtonsoft.Json;
+
+using NUnit.Framework;
+
+namespace LogExpert.Tests.ConfigManagerTests;
+
+[TestFixture]
+public class SelectionHighlightSettingsTests
+{
+ [Test]
+ public void CustomAppearance_SurvivesRoundTrip ()
+ {
+ var preferences = new Preferences
+ {
+ SelectionHighlight = new() { Outline = true, CustomColor = Color.FromArgb(25, 100, 180) }
+ };
+
+ var restored = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(preferences));
+
+ Assert.That(restored.SelectionHighlight.Outline, Is.True);
+ Assert.That(restored.SelectionHighlight.CustomColor, Is.EqualTo(Color.FromArgb(25, 100, 180)));
+ }
+
+ [Test]
+ public void OlderSettings_KeepSystemFilledSelection ()
+ {
+ var preferences = JsonConvert.DeserializeObject("{}");
+
+ Assert.That(preferences.SelectionHighlight.Outline, Is.False);
+ Assert.That(preferences.SelectionHighlight.CustomColor, Is.Null);
+ }
+}
\ No newline at end of file
diff --git a/src/LogExpert.Tests/UI/SelectionHighlightDialogTests.cs b/src/LogExpert.Tests/UI/SelectionHighlightDialogTests.cs
new file mode 100644
index 00000000..2feb61fb
--- /dev/null
+++ b/src/LogExpert.Tests/UI/SelectionHighlightDialogTests.cs
@@ -0,0 +1,88 @@
+using LogExpert.Core.Config;
+using LogExpert.Core.Interfaces;
+using LogExpert.Dialogs;
+
+using Moq;
+
+using NUnit.Framework;
+
+namespace LogExpert.Tests.UI;
+
+[TestFixture]
+[Apartment(ApartmentState.STA)]
+[System.Runtime.Versioning.SupportedOSPlatform("windows")]
+public class SelectionHighlightDialogTests
+{
+ [TestCase("en-US", 1f)]
+ [TestCase("de-DE", 1.5f)]
+ public void SelectionControls_FitDialogWithoutAnOpenFile (string culture, float scale)
+ {
+ var previousCulture = Thread.CurrentThread.CurrentUICulture;
+ try
+ {
+ Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(culture);
+
+ var settings = new Settings();
+ settings.Preferences.SelectionHighlight.CustomColor = Color.Yellow;
+
+ var config = new Mock();
+ _ = config.SetupGet(c => c.Settings).Returns(settings);
+
+ using var dialog = new HighlightDialog(config.Object) { HighlightGroupList = [] };
+ dialog.Scale(new SizeF(scale, scale));
+ dialog.Show();
+
+ foreach (var name in new[] { "checkBoxSelectionOutline", "btnSelectionColor", "btnResetSelectionColor", "btnOk", "btnCancel" })
+ {
+ var control = dialog.Controls.Find(name, true).Single();
+
+ Assert.That(control.Visible, Is.True, name);
+ Assert.That(control.Parent.ClientRectangle.Contains(control.Bounds), Is.True, name);
+ Assert.That(dialog.RectangleToScreen(dialog.ClientRectangle).Contains(control.RectangleToScreen(control.ClientRectangle)), Is.True, name);
+ }
+
+ using var bitmap = new Bitmap(dialog.Width, dialog.Height);
+ dialog.DrawToBitmap(bitmap, new Rectangle(Point.Empty, bitmap.Size));
+
+ var path = Path.Join(TestContext.CurrentContext.WorkDirectory, $"selection-highlight-{culture}.png");
+ bitmap.Save(path, System.Drawing.Imaging.ImageFormat.Png);
+
+ TestContext.AddTestAttachment(path);
+ ((Button)dialog.Controls.Find("btnResetSelectionColor", true).Single()).PerformClick();
+
+ Assert.That(dialog.SelectionHighlight.CustomColor, Is.Null);
+ Assert.That(settings.Preferences.SelectionHighlight.CustomColor, Is.EqualTo(Color.Yellow));
+ }
+ finally
+ {
+ Thread.CurrentThread.CurrentUICulture = previousCulture;
+ }
+ }
+
+ [TestCase(DialogResult.OK)]
+ [TestCase(DialogResult.Cancel)]
+ public void EditingSelection_LeavesLiveSettingsUntouchedUntilCallerAccepts (DialogResult result)
+ {
+ var settings = new Settings();
+
+ var config = new Mock();
+ _ = config.SetupGet(c => c.Settings).Returns(settings);
+
+ using var dialog = new HighlightDialog(config.Object) { HighlightGroupList = [] };
+ dialog.Show();
+
+ var outline = (CheckBox)dialog.Controls.Find("checkBoxSelectionOutline", true).Single();
+ outline.Checked = true;
+ ((Button)dialog.Controls.Find(result == DialogResult.OK ? "btnOk" : "btnCancel", true).Single()).PerformClick();
+
+ Assert.That(dialog.DialogResult, Is.EqualTo(result));
+ Assert.That(settings.Preferences.SelectionHighlight.Outline, Is.False);
+
+ if (result == DialogResult.OK)
+ {
+ Assert.That(dialog.SelectionHighlight.Outline, Is.True);
+ }
+
+ config.Verify(c => c.Save(It.IsAny()), Times.Never);
+ }
+}
\ No newline at end of file
diff --git a/src/LogExpert.Tests/UI/SelectionPainterTests.cs b/src/LogExpert.Tests/UI/SelectionPainterTests.cs
new file mode 100644
index 00000000..5b12437e
--- /dev/null
+++ b/src/LogExpert.Tests/UI/SelectionPainterTests.cs
@@ -0,0 +1,173 @@
+using LogExpert.Core.Config;
+using LogExpert.UI.Entities;
+using LogExpert.UI.Controls;
+using LogExpert.UI.Interface;
+using LogExpert.Core.Classes.Highlight;
+using LogExpert.Core.Entities;
+using ColumnizerLib;
+
+using Moq;
+
+using NUnit.Framework;
+
+namespace LogExpert.Tests.UI;
+
+[TestFixture]
+[Apartment(ApartmentState.STA)]
+[System.Runtime.Versioning.SupportedOSPlatform("windows")]
+public class SelectionPainterTests
+{
+ [TestCase(true)]
+ [TestCase(false)]
+ public void LogContentPainting_OutlinePreservesLineAndWordBackgrounds (bool outline)
+ {
+ var settings = new SelectionHighlightSettings { Outline = outline, CustomColor = Color.Magenta };
+ var context = new Mock();
+ context.SetupGet(c => c.SelectionHighlight).Returns(settings);
+ context.Setup(c => c.GetLogLineMemory(It.IsAny())).Returns(new LogLine("WORD plain", 0));
+ context.Setup(c => c.FindHighlightEntry(It.IsAny(), true))
+ .Returns(new HighlightEntry { BackgroundColor = Color.LightSalmon, ForegroundColor = Color.Black });
+ context.Setup(c => c.FindHighlightMatches(It.IsAny())).Returns(() => new List
+ {
+ new() { StartPos = 0, Length = 4, HighlightEntry = new() { IsWordMatch = true, BackgroundColor = Color.Yellow, ForegroundColor = Color.Red } }
+ });
+ context.SetupGet(c => c.NormalFont).Returns(() => new Font("Consolas", 10));
+ context.SetupGet(c => c.BoldFont).Returns(() => new Font("Consolas", 10, FontStyle.Bold));
+ using var form = new Form { ClientSize = new Size(320, 180) };
+ using var grid = new BufferedDataGridView
+ {
+ Dock = DockStyle.Fill, AllowUserToAddRows = false, RowHeadersVisible = false,
+ ColumnHeadersVisible = false, CellBorderStyle = DataGridViewCellBorderStyle.None,
+ SelectionMode = DataGridViewSelectionMode.FullRowSelect, SelectionHighlight = settings
+ };
+ grid.Columns.Add(new DataGridViewTextBoxColumn { Width = 280 });
+ grid.RowCount = 2;
+ grid.CellValueNeeded += (_, e) => e.Value = new Column { FullValue = "WORD plain".AsMemory() };
+ grid.CellPainting += (_, e) => PaintHelper.CellPainting(context.Object, grid.Focused, e.RowIndex, e.ColumnIndex, e);
+ form.Controls.Add(grid);
+ form.Show();
+ grid.Rows[0].Selected = true;
+ using var bitmap = new Bitmap(grid.Width, grid.Height);
+ grid.DrawToBitmap(bitmap, grid.ClientRectangle);
+ var bounds = grid.GetCellDisplayRectangle(0, 0, false);
+ Assert.That(bitmap.GetPixel(bounds.Left + 4, bounds.Top + 3).ToArgb(), Is.EqualTo((outline ? Color.Yellow : Color.Magenta).ToArgb()));
+ Assert.That(bitmap.GetPixel(bounds.Right - 10, bounds.Top + 3).ToArgb(), Is.EqualTo((outline ? Color.LightSalmon : Color.Magenta).ToArgb()));
+ }
+
+ [Test]
+ public void PaintedBlock_HasNoInternalEdge_AndErasesOldEdgesAfterSelectionChanges ()
+ {
+ using var form = new Form { ClientSize = new Size(320, 220) };
+ using var grid = new BufferedDataGridView
+ {
+ Dock = DockStyle.Fill,
+ AllowUserToAddRows = false,
+ RowHeadersVisible = false,
+ ColumnHeadersVisible = false,
+ CellBorderStyle = DataGridViewCellBorderStyle.None,
+ SelectionMode = DataGridViewSelectionMode.FullRowSelect,
+ SelectionHighlight = new() { Outline = true, CustomColor = Color.Magenta }
+ };
+ grid.Columns.Add("a", "A");
+ grid.Columns.Add("b", "B");
+ grid.Rows.Add(4);
+ // Supply highlighted content beneath the selection overlay.
+ grid.DefaultCellStyle.BackColor = Color.Khaki;
+ grid.DefaultCellStyle.SelectionBackColor = Color.Khaki;
+ form.Controls.Add(grid);
+ form.Show();
+ grid.ClearSelection();
+ grid.Rows[0].Selected = true;
+ grid.Rows[1].Selected = true;
+ using var bitmap = new Bitmap(grid.Width, grid.Height);
+ grid.DrawToBitmap(bitmap, grid.ClientRectangle);
+ var first = grid.GetCellDisplayRectangle(0, 0, false);
+ var second = grid.GetCellDisplayRectangle(0, 1, false);
+
+ Assert.That(bitmap.GetPixel(first.Left + 20, first.Top).ToArgb(), Is.EqualTo(Color.Magenta.ToArgb()));
+ Assert.That(bitmap.GetPixel(first.Left + 20, first.Bottom - 1).ToArgb(), Is.EqualTo(Color.Khaki.ToArgb()));
+ Assert.That(bitmap.GetPixel(second.Left + 20, second.Bottom - 1).ToArgb(), Is.EqualTo(Color.Magenta.ToArgb()));
+
+ grid.Rows[1].Selected = false;
+ grid.DrawToBitmap(bitmap, grid.ClientRectangle);
+ Assert.That(bitmap.GetPixel(first.Left + 20, first.Bottom - 1).ToArgb(), Is.EqualTo(Color.Magenta.ToArgb()));
+ Assert.That(bitmap.GetPixel(second.Left + 20, second.Bottom - 1).ToArgb(), Is.EqualTo(Color.Khaki.ToArgb()));
+ }
+
+ [Test]
+ public void Outline_PreservesBlackAndColoredText ()
+ {
+ var style = SelectionPainter.GetStyle(new() { Outline = true, CustomColor = Color.Yellow }, true, true, Color.Blue, false);
+ Assert.That(style.FillBackground, Is.False);
+ Assert.That(style.Foreground(Color.Black), Is.EqualTo(Color.Black));
+ Assert.That(style.Foreground(Color.Red), Is.EqualTo(Color.Red));
+ }
+
+ [TestCase(true, false)]
+ [TestCase(false, false)]
+ [TestCase(false, true)]
+ public void CustomFill_UsesReadableTextEvenWithoutFocus (bool focused, bool darkMode)
+ {
+ var style = SelectionPainter.GetStyle(new() { CustomColor = Color.Yellow }, true, focused, Color.Blue, darkMode);
+ Assert.That(style.Background, Is.EqualTo(Color.Yellow));
+ Assert.That(style.Foreground(Color.White), Is.EqualTo(Color.Black));
+ }
+
+ [Test]
+ public void DefaultFill_PreservesLegacyForegroundRules ()
+ {
+ var style = SelectionPainter.GetStyle(new(), true, true, Color.Blue, false);
+ Assert.That(style.Foreground(Color.Black), Is.EqualTo(Color.White));
+ Assert.That(style.Foreground(Color.Red), Is.EqualTo(Color.Red));
+ }
+
+ [Test]
+ public void DisjointRows_EachHaveTopAndBottomBoundaries ()
+ {
+ using var grid = CreateGrid();
+ grid.Rows[0].Selected = true;
+ grid.Rows[2].Selected = true;
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 0, 0), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Bottom | SelectionEdges.Left));
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 2, 0), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Bottom | SelectionEdges.Left));
+ }
+
+ [Test]
+ public void CellSelection_UsesVisibleDisplayOrder ()
+ {
+ using var grid = CreateGrid();
+ grid.SelectionMode = DataGridViewSelectionMode.CellSelect;
+ grid.Columns.Add("hidden", "Hidden");
+ grid.Columns[2].Visible = false;
+ grid.Columns[1].DisplayIndex = 0;
+ grid[0, 0].Selected = true;
+ grid[1, 0].Selected = true;
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 0, 1), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Bottom | SelectionEdges.Left));
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 0, 0), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Bottom | SelectionEdges.Right));
+
+ grid[1, 0].Selected = false;
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 0, 0), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Bottom | SelectionEdges.Left | SelectionEdges.Right));
+ }
+
+ [Test]
+ public void AdjacentRows_HaveOnlyAnExternalOutline ()
+ {
+ using var grid = CreateGrid();
+ grid.Rows[0].Selected = true;
+ grid.Rows[1].Selected = true;
+
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 0, 0), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Left));
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 0, 1), Is.EqualTo(SelectionEdges.Top | SelectionEdges.Right));
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 1, 0), Is.EqualTo(SelectionEdges.Bottom | SelectionEdges.Left));
+ Assert.That(SelectionPainter.GetOutlineEdges(grid, 2, 0), Is.EqualTo(SelectionEdges.None));
+ }
+
+ private static DataGridView CreateGrid ()
+ {
+ var grid = new DataGridView { AllowUserToAddRows = false, SelectionMode = DataGridViewSelectionMode.FullRowSelect };
+ grid.Columns.Add("a", "A");
+ grid.Columns.Add("b", "B");
+ grid.Rows.Add(4);
+ grid.ClearSelection();
+ return grid;
+ }
+}
\ No newline at end of file
diff --git a/src/LogExpert.UI/Controls/BufferedDataGridView.cs b/src/LogExpert.UI/Controls/BufferedDataGridView.cs
index 5ef1f004..6dccc167 100644
--- a/src/LogExpert.UI/Controls/BufferedDataGridView.cs
+++ b/src/LogExpert.UI/Controls/BufferedDataGridView.cs
@@ -3,7 +3,9 @@
using System.Runtime.Versioning;
using LogExpert.Core.Entities;
+using LogExpert.Core.Config;
using LogExpert.Core.EventArguments;
+using LogExpert.UI.Entities;
using NLog;
@@ -75,6 +77,9 @@ public BufferedDataGridView ()
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public bool PaintWithOverlays { get; set; }
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public SelectionHighlightSettings SelectionHighlight { get; set; } = new();
+
#endregion
#region Public methods
@@ -134,6 +139,37 @@ private void EnsureDrawingResources ()
#region Overrides
+ protected override void OnSelectionChanged (EventArgs e)
+ {
+ base.OnSelectionChanged(e);
+ if (SelectionHighlight?.Outline == true)
+ {
+ // A changed cell can also remove an edge on a still-selected neighbor.
+ Invalidate();
+ }
+ }
+
+ protected override void OnGotFocus (EventArgs e)
+ {
+ base.OnGotFocus(e);
+ Invalidate();
+ }
+
+ protected override void OnScroll (ScrollEventArgs e)
+ {
+ base.OnScroll(e);
+ if (SelectionHighlight?.Outline == true)
+ {
+ Invalidate();
+ }
+ }
+
+ protected override void OnLostFocus (EventArgs e)
+ {
+ base.OnLostFocus(e);
+ Invalidate();
+ }
+
protected override void Dispose (bool disposing)
{
if (disposing)
@@ -161,6 +197,8 @@ protected override void OnPaint (PaintEventArgs e)
{
base.OnPaint(e);
}
+
+ SelectionPainter.PaintOutline(this, e, SelectionHighlight);
}
catch (Exception ex)
{
diff --git a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
index c5c23c35..38e11b04 100644
--- a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
+++ b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs
@@ -421,6 +421,8 @@ public bool IsMultiFile
public Preferences Preferences => ConfigManager.Settings.Preferences;
+ SelectionHighlightSettings ILogPaintContextUI.SelectionHighlight => Preferences.SelectionHighlight;
+
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string GivenFileName { get; set; }
@@ -2237,6 +2239,8 @@ private void OnSetBookmarksOnSelectedLinesToolStripMenuItemClick (object sender,
private void OnParentHighlightSettingsChanged (object sender, EventArgs e)
{
+ dataGridView.SelectionHighlight = Preferences.SelectionHighlight;
+ filterGridView.SelectionHighlight = Preferences.SelectionHighlight;
var groupName = _guiStateArgs.HighlightGroupName;
SetCurrentHighlightGroup(groupName);
}
@@ -3514,12 +3518,12 @@ private void AdjustColumnWidthsForControlCharSubstitution (BufferedDataGridView
}
}
- private void PaintCell (DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry)
+ private void PaintCell (DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry, SelectionCellStyle selection)
{
- PaintHighlightedCell(e, groundEntry);
+ PaintHighlightedCell(e, groundEntry, selection);
}
- private void PaintHighlightedCell (DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry)
+ private void PaintHighlightedCell (DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry, SelectionCellStyle selection)
{
var column = e.Value as IColumnMemory;
@@ -3618,15 +3622,8 @@ private void PaintHighlightedCell (DataGridViewCellPaintingEventArgs e, Highligh
wordSize.Height = e.CellBounds.Height;
Rectangle wordRect = new(wordPos, wordSize);
- var foreColor = segment.ForeColor;
- if (e.State.HasFlag(DataGridViewElementStates.Selected))
- {
- if (foreColor.Equals(Color.Black))
- {
- foreColor = Color.White;
- }
- }
- else
+ var foreColor = selection.Foreground(segment.ForeColor);
+ if (!selection.FillBackground)
{
if (bgBrush != null && !segment.NoBackground)
{
@@ -6256,12 +6253,9 @@ public void CellPainting (bool focused, int rowIndex, int columnIndex, bool isFi
var entry = FindFirstNoWordMatchHighlightEntry(line);
e.Graphics.SetClip(e.CellBounds);
- if (e.State.HasFlag(DataGridViewElementStates.Selected))
- {
- using var brush = PaintHelper.GetBrushForFocusedControl(focused, e.CellStyle.SelectionBackColor, Application.IsDarkModeEnabled);
- e.Graphics.FillRectangle(brush, e.CellBounds);
- }
- else
+ var selection = SelectionPainter.GetStyle(Preferences.SelectionHighlight,
+ e.State.HasFlag(DataGridViewElementStates.Selected), focused, e.CellStyle.SelectionBackColor, Application.IsDarkModeEnabled);
+ if (!selection.PaintBackground(e))
{
e.CellStyle.BackColor = PaintHelper.GetBackColorFromHighlightEntry(entry, Application.IsDarkModeEnabled);
e.PaintBackground(e.ClipBounds, false);
@@ -6269,11 +6263,12 @@ public void CellPainting (bool focused, int rowIndex, int columnIndex, bool isFi
if (DebugOptions.DisableWordHighlight)
{
+ e.CellStyle.SelectionForeColor = selection.Foreground(e.CellStyle.ForeColor);
e.PaintContent(e.CellBounds);
}
else
{
- PaintCell(e, entry);
+ PaintCell(e, entry, selection);
}
if (columnIndex == 0)
@@ -7346,6 +7341,8 @@ public void Reload ()
public void PreferencesChanged (Font font, bool setLastColumnWidth, int lastColumnWidth, bool isLoadTime, SettingsFlags flags)
{
+ dataGridView.SelectionHighlight = Preferences.SelectionHighlight;
+ filterGridView.SelectionHighlight = Preferences.SelectionHighlight;
if ((flags & SettingsFlags.GuiOrColors) == SettingsFlags.GuiOrColors)
{
font ??= Preferences.Font ?? new Font(FontFamily.GenericMonospace, 9f);
@@ -7733,4 +7730,4 @@ public void RefreshLogView ()
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/src/LogExpert.UI/Dialogs/BookmarkWindow.cs b/src/LogExpert.UI/Dialogs/BookmarkWindow.cs
index 2dd0c288..104e25dd 100644
--- a/src/LogExpert.UI/Dialogs/BookmarkWindow.cs
+++ b/src/LogExpert.UI/Dialogs/BookmarkWindow.cs
@@ -197,6 +197,11 @@ public void SetBookmarkData (IBookmarkData bookmarkData)
public void PreferencesChanged (Font font, bool setLastColumnWidth, int lastColumnWidth, SettingsFlags flags)
{
+ if (_logPaintContext != null)
+ {
+ bookmarkDataGridView.SelectionHighlight = _logPaintContext.SelectionHighlight;
+ bookmarkDataGridView.Invalidate();
+ }
if ((flags & SettingsFlags.GuiOrColors) == SettingsFlags.GuiOrColors)
{
SetFont(font);
@@ -218,6 +223,7 @@ public void SetCurrentFile (IFileViewContext ctx)
{
_logView = ctx.LogView;
_logPaintContext = (ILogPaintContextUI)ctx.LogPaintContext;
+ bookmarkDataGridView.SelectionHighlight = _logPaintContext.SelectionHighlight;
}
SetColumnizer(ctx.LogView.CurrentColumnizer);
@@ -671,4 +677,4 @@ private void OnBookmarkWindowSizeChanged (object sender, EventArgs e)
}
#endregion
-}
\ No newline at end of file
+}
diff --git a/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.Designer.cs b/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.Designer.cs
index bc99f4a9..e17c4eb3 100644
--- a/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.Designer.cs
+++ b/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.Designer.cs
@@ -53,6 +53,11 @@ private void InitializeComponent ()
toolTip = new ToolTip(components);
pnlBackground = new Panel();
groupBoxGroups = new GroupBox();
+ groupBoxSelection = new GroupBox();
+ checkBoxSelectionOutline = new CheckBox();
+ btnSelectionColor = new Button();
+ btnResetSelectionColor = new Button();
+ selectionControls = new FlowLayoutPanel();
pnlBackground.SuspendLayout();
groupBoxGroups.SuspendLayout();
SuspendLayout();
@@ -139,7 +144,7 @@ private void InitializeComponent ()
//
btnOk.Anchor = AnchorStyles.Top;
btnOk.DialogResult = DialogResult.OK;
- btnOk.Location = new Point(387, 364);
+ btnOk.Location = new Point(387, 480);
btnOk.Margin = new Padding(4, 5, 4, 5);
btnOk.Name = "btnOk";
btnOk.Size = new Size(85, 35);
@@ -152,7 +157,7 @@ private void InitializeComponent ()
//
btnCancel.Anchor = AnchorStyles.Top;
btnCancel.DialogResult = DialogResult.Cancel;
- btnCancel.Location = new Point(478, 364);
+ btnCancel.Location = new Point(478, 480);
btnCancel.Margin = new Padding(4, 5, 4, 5);
btnCancel.Name = "btnCancel";
btnCancel.Size = new Size(85, 35);
@@ -168,7 +173,7 @@ private void InitializeComponent ()
// btnExportGroup
//
btnExportGroup.Anchor = AnchorStyles.Top;
- btnExportGroup.Location = new Point(108, 364);
+ btnExportGroup.Location = new Point(108, 480);
btnExportGroup.Margin = new Padding(4, 5, 4, 5);
btnExportGroup.Name = "btnExportGroup";
btnExportGroup.Size = new Size(85, 35);
@@ -181,7 +186,7 @@ private void InitializeComponent ()
// btnImportGroup
//
btnImportGroup.Anchor = AnchorStyles.Top;
- btnImportGroup.Location = new Point(12, 364);
+ btnImportGroup.Location = new Point(12, 480);
btnImportGroup.Margin = new Padding(4, 5, 4, 5);
btnImportGroup.Name = "btnImportGroup";
btnImportGroup.Size = new Size(85, 35);
@@ -297,9 +302,10 @@ private void InitializeComponent ()
pnlBackground.Controls.Add(btnOk);
pnlBackground.Controls.Add(btnCancel);
pnlBackground.Controls.Add(groupBoxGroups);
+ pnlBackground.Controls.Add(groupBoxSelection);
pnlBackground.Location = new Point(0, 0);
pnlBackground.Name = "pnlBackground";
- pnlBackground.Size = new Size(576, 511);
+ pnlBackground.Size = new Size(576, 528);
pnlBackground.TabIndex = 23;
//
// groupBoxGroups
@@ -320,12 +326,38 @@ private void InitializeComponent ()
groupBoxGroups.TabIndex = 22;
groupBoxGroups.TabStop = false;
groupBoxGroups.Text = "Groups";
+ // Selection appearance is application-wide, separate from the group editor.
+ groupBoxSelection.Location = new Point(12, 364);
+ groupBoxSelection.Size = new Size(552, 108);
+ groupBoxSelection.TabIndex = 8;
+ groupBoxSelection.Controls.Add(selectionControls);
+ selectionControls.Dock = DockStyle.Fill;
+ selectionControls.Padding = new Padding(6);
+ selectionControls.Controls.Add(checkBoxSelectionOutline);
+ selectionControls.Controls.Add(btnSelectionColor);
+ selectionControls.Controls.Add(btnResetSelectionColor);
+ selectionControls.SetFlowBreak(checkBoxSelectionOutline, true);
+ checkBoxSelectionOutline.Name = "checkBoxSelectionOutline";
+ checkBoxSelectionOutline.AutoSize = true;
+ checkBoxSelectionOutline.TabIndex = 0;
+ btnSelectionColor.AutoSize = true;
+ btnSelectionColor.Name = "btnSelectionColor";
+ btnSelectionColor.AutoSizeMode = AutoSizeMode.GrowAndShrink;
+ btnSelectionColor.Padding = new Padding(4);
+ btnSelectionColor.TabIndex = 1;
+ btnSelectionColor.Click += OnSelectionColorClick;
+ btnResetSelectionColor.AutoSize = true;
+ btnResetSelectionColor.Name = "btnResetSelectionColor";
+ btnResetSelectionColor.AutoSizeMode = AutoSizeMode.GrowAndShrink;
+ btnResetSelectionColor.Padding = new Padding(4);
+ btnResetSelectionColor.TabIndex = 2;
+ btnResetSelectionColor.Click += OnResetSelectionColorClick;
//
// HighlightDialog
//
AcceptButton = btnOk;
CancelButton = btnCancel;
- ClientSize = new Size(576, 411);
+ ClientSize = new Size(576, 528);
Controls.Add(pnlBackground);
DoubleBuffered = true;
helpProvider.SetHelpKeyword(this, "Highlighting.htm");
@@ -335,7 +367,7 @@ private void InitializeComponent ()
Margin = new Padding(4, 5, 4, 5);
MaximizeBox = false;
MinimizeBox = false;
- MinimumSize = new Size(592, 430);
+ MinimumSize = new Size(592, 567);
Name = "HighlightDialog";
helpProvider.SetShowHelp(this, true);
StartPosition = FormStartPosition.CenterParent;
@@ -348,6 +380,11 @@ private void InitializeComponent ()
}
#endregion
+ private GroupBox groupBoxSelection;
+ private FlowLayoutPanel selectionControls;
+ private CheckBox checkBoxSelectionOutline;
+ private Button btnSelectionColor;
+ private Button btnResetSelectionColor;
private System.Windows.Forms.ListBox listBoxHighlight;
private System.Windows.Forms.Button btnAdd;
diff --git a/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.cs b/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.cs
index 89b324de..89afc763 100644
--- a/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.cs
+++ b/src/LogExpert.UI/Dialogs/Highlight/HighlightDialog.cs
@@ -3,6 +3,7 @@
using System.Security;
using ColumnizerLib;
+using LogExpert.Core.Config;
using LogExpert.Core.Classes.Highlight;
using LogExpert.Core.Entities;
@@ -20,6 +21,7 @@ internal partial class HighlightDialog : Form
private HighlightGroup _currentGroup;
private List _highlightGroupList;
+ private Color? _selectionColor;
#endregion
@@ -37,6 +39,9 @@ public HighlightDialog (IConfigManager configManager)
ApplyResources();
ConfigManager = configManager;
+ _selectionColor = configManager.Settings.Preferences.SelectionHighlight.CustomColor;
+ checkBoxSelectionOutline.Checked = configManager.Settings.Preferences.SelectionHighlight.Outline;
+ UpdateSelectionColorPreview();
Load += OnHighlightDialogLoad;
listBoxHighlight.DrawItem += OnHighlightListBoxDrawItem;
@@ -65,6 +70,10 @@ private void ApplyResources ()
labelAssignNamesToGroups.Text = Resources.HighlightDialog_UI_Label_AssignNamesToGroups;
groupBoxGroups.Text = Resources.HighlightDialog_UI_GroupBox_Groups;
+ groupBoxSelection.Text = Resources.HighlightDialog_UI_SelectionHighlight;
+ checkBoxSelectionOutline.Text = Resources.HighlightDialog_UI_OutlineSelectedBlocks;
+ btnSelectionColor.Text = Resources.HighlightDialog_UI_ChangeSelectionColor;
+ btnResetSelectionColor.Text = Resources.HighlightDialog_UI_ResetSelectionColor;
}
#endregion
@@ -94,10 +103,40 @@ public List HighlightGroupList
private IConfigManager ConfigManager { get; }
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public SelectionHighlightSettings SelectionHighlight => new()
+ {
+ Outline = checkBoxSelectionOutline.Checked,
+ CustomColor = _selectionColor
+ };
+
#endregion
#region Event handling Methods
+ private void OnSelectionColorClick (object sender, EventArgs e)
+ {
+ using var dialog = new ColorDialog { Color = _selectionColor ?? SystemColors.Highlight, FullOpen = true };
+ if (dialog.ShowDialog(this) == DialogResult.OK)
+ {
+ _selectionColor = dialog.Color;
+ UpdateSelectionColorPreview();
+ }
+ }
+
+ private void OnResetSelectionColorClick (object sender, EventArgs e)
+ {
+ _selectionColor = null;
+ UpdateSelectionColorPreview();
+ }
+
+ private void UpdateSelectionColorPreview ()
+ {
+ btnSelectionColor.BackColor = _selectionColor ?? SystemColors.Highlight;
+ btnSelectionColor.ForeColor = PaintHelper.GetForeColorBasedOnBackColor(btnSelectionColor.BackColor);
+ btnResetSelectionColor.Enabled = _selectionColor.HasValue;
+ }
+
private void OnAddButtonClick (object sender, EventArgs e)
{
if (_currentGroup == null)
diff --git a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs
index 2e44ec9e..9c9647c1 100644
--- a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs
+++ b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs
@@ -915,7 +915,7 @@ private void RemoveAndDisposeLogWindow (LogWindow.LogWindow logWindow, bool dont
[SupportedOSPlatform("windows")]
private void ShowHighlightSettingsDialog ()
{
- HighlightDialog dlg = new(ConfigManager)
+ using HighlightDialog dlg = new(ConfigManager)
{
KeywordActionList = PluginRegistry.PluginRegistry.Instance.RegisteredKeywordActions,
Owner = this,
@@ -931,6 +931,7 @@ private void ShowHighlightSettingsDialog ()
HighlightGroupList = dlg.HighlightGroupList;
FillHighlightComboBox();
ConfigManager.Settings.Preferences.HighlightGroupList = HighlightGroupList;
+ ConfigManager.Settings.Preferences.SelectionHighlight = dlg.SelectionHighlight;
ConfigManager.Save(SettingsFlags.HighlightSettings);
OnHighlightSettingsChanged();
}
diff --git a/src/LogExpert.UI/Entities/PaintHelper.cs b/src/LogExpert.UI/Entities/PaintHelper.cs
index a3425ea5..404c28d2 100644
--- a/src/LogExpert.UI/Entities/PaintHelper.cs
+++ b/src/LogExpert.UI/Entities/PaintHelper.cs
@@ -44,12 +44,9 @@ public static void CellPainting (ILogPaintContextUI logPaintCtx, bool focused, i
var entry = logPaintCtx.FindHighlightEntry(line, true);
e.Graphics.SetClip(e.CellBounds);
- if (e.State.HasFlag(DataGridViewElementStates.Selected))
- {
- using var brush = GetBrushForFocusedControl(focused, e.CellStyle.SelectionBackColor, Application.IsDarkModeEnabled);
- e.Graphics.FillRectangle(brush, e.CellBounds);
- }
- else
+ var selection = SelectionPainter.GetStyle(logPaintCtx.SelectionHighlight,
+ e.State.HasFlag(DataGridViewElementStates.Selected), focused, e.CellStyle.SelectionBackColor, Application.IsDarkModeEnabled);
+ if (!selection.PaintBackground(e))
{
e.CellStyle.BackColor = GetBackColorFromHighlightEntry(entry, Application.IsDarkModeEnabled);
e.PaintBackground(e.ClipBounds, false);
@@ -57,11 +54,12 @@ public static void CellPainting (ILogPaintContextUI logPaintCtx, bool focused, i
if (DebugOptions.DisableWordHighlight)
{
+ e.CellStyle.SelectionForeColor = selection.Foreground(e.CellStyle.ForeColor);
e.PaintContent(e.CellBounds);
}
else
{
- PaintCell(logPaintCtx, e, entry);
+ PaintCell(logPaintCtx, e, entry, selection);
}
if (e.ColumnIndex == 0)
@@ -110,14 +108,7 @@ public static Color GetForeColorFromHighlightEntry (HighlightEntry? entry, bool
[SupportedOSPlatform("windows")]
public static Brush GetBrushForFocusedControl (bool focused, Color selectionColor, bool darkMode)
{
- if (focused)
- {
- return new SolidBrush(selectionColor);
- }
-
- return darkMode
- ? new SolidBrush(Color.FromArgb(255, 90, 90, 90)) // dark gray
- : new SolidBrush(Color.FromArgb(255, 170, 170, 170)); // light gray
+ return new SolidBrush(SelectionPainter.GetStyle(new(), true, focused, selectionColor, darkMode).Background);
}
[SupportedOSPlatform("windows")]
@@ -374,13 +365,13 @@ private static int GetBorderSize (DataGridViewAdvancedCellBorderStyle borderStyl
#region Private Methods
[SupportedOSPlatform("windows")]
- private static void PaintCell (ILogPaintContextUI logPaintCtx, DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry)
+ private static void PaintCell (ILogPaintContextUI logPaintCtx, DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry, SelectionCellStyle selection)
{
- PaintHighlightedCell(logPaintCtx, e, groundEntry);
+ PaintHighlightedCell(logPaintCtx, e, groundEntry, selection);
}
[SupportedOSPlatform("windows")]
- private static void PaintHighlightedCell (ILogPaintContextUI logPaintCtx, DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry)
+ private static void PaintHighlightedCell (ILogPaintContextUI logPaintCtx, DataGridViewCellPaintingEventArgs e, HighlightEntry groundEntry, SelectionCellStyle selection)
{
var value = e.Value ?? string.Empty;
@@ -476,15 +467,8 @@ private static void PaintHighlightedCell (ILogPaintContextUI logPaintCtx, DataGr
wordSize.Height = e.CellBounds.Height;
Rectangle wordRect = new(wordPos, wordSize);
- var foreColor = matchEntry.HighlightEntry.ForegroundColor;
- if (e.State.HasFlag(DataGridViewElementStates.Selected))
- {
- if (foreColor.Equals(Color.Black))
- {
- foreColor = Color.White;
- }
- }
- else
+ var foreColor = selection.Foreground(matchEntry.HighlightEntry.ForegroundColor);
+ if (!selection.FillBackground)
{
if (bgBrush != null && !matchEntry.HighlightEntry.NoBackground)
{
@@ -573,4 +557,4 @@ private static IList MergeHighlightMatchEntries (IListSelection styling and external boundaries shared by all log grids.
+[SupportedOSPlatform("windows")]
+internal static class SelectionPainter
+{
+ public static SelectionCellStyle GetStyle (SelectionHighlightSettings settings, bool selected, bool focused, Color systemColor, bool darkMode)
+ {
+ var color = settings.CustomColor ?? (focused ? systemColor : darkMode ? Color.FromArgb(90, 90, 90) : Color.FromArgb(170, 170, 170));
+ return new(selected && !settings.Outline, color, settings.CustomColor.HasValue);
+ }
+
+ public static SelectionEdges GetOutlineEdges (DataGridView grid, int row, int column)
+ {
+ if (!grid[column, row].Selected)
+ {
+ return SelectionEdges.None;
+ }
+
+ var previousRow = grid.Rows.GetPreviousRow(row, DataGridViewElementStates.Visible);
+ var nextRow = grid.Rows.GetNextRow(row, DataGridViewElementStates.Visible);
+ var previousColumn = grid.Columns.GetPreviousColumn(grid.Columns[column], DataGridViewElementStates.Visible, DataGridViewElementStates.None);
+ var nextColumn = grid.Columns.GetNextColumn(grid.Columns[column], DataGridViewElementStates.Visible, DataGridViewElementStates.None);
+ var edges = SelectionEdges.None;
+ if (previousRow < 0 || !grid[column, previousRow].Selected)
+ {
+ edges |= SelectionEdges.Top;
+ }
+
+ if (nextRow < 0 || !grid[column, nextRow].Selected)
+ {
+ edges |= SelectionEdges.Bottom;
+ }
+
+ if (previousColumn == null || !grid[previousColumn.Index, row].Selected)
+ {
+ edges |= SelectionEdges.Left;
+ }
+
+ if (nextColumn == null || !grid[nextColumn.Index, row].Selected)
+ {
+ edges |= SelectionEdges.Right;
+ }
+
+ return edges;
+ }
+
+ public static void PaintOutline (DataGridView grid, PaintEventArgs e, SelectionHighlightSettings settings)
+ {
+ if (!settings.Outline || grid.RowCount == 0 || grid.ColumnCount == 0)
+ {
+ return;
+ }
+
+ var style = GetStyle(settings, true, grid.Focused, grid.DefaultCellStyle.SelectionBackColor, Application.IsDarkModeEnabled);
+ using var pen = new Pen(style.Background, Math.Max(1, grid.DeviceDpi / 96f));
+ var state = e.Graphics.Save();
+ try
+ {
+ // Cell painting changes the graphics clip. Restore the update region before
+ // drawing boundaries, and clip each cell to its actual visible portion.
+ e.Graphics.SetClip(e.ClipRectangle);
+ for (var row = grid.Rows.GetFirstRow(DataGridViewElementStates.Displayed); row >= 0;
+ row = grid.Rows.GetNextRow(row, DataGridViewElementStates.Displayed))
+ {
+ foreach (DataGridViewColumn column in grid.Columns)
+ {
+ if (!column.Visible)
+ {
+ continue;
+ }
+
+ var bounds = grid.GetCellDisplayRectangle(column.Index, row, false);
+ var visible = grid.GetCellDisplayRectangle(column.Index, row, true);
+ if (visible.IsEmpty || !visible.IntersectsWith(e.ClipRectangle))
+ {
+ continue;
+ }
+
+ var edges = GetOutlineEdges(grid, row, column.Index);
+ if (edges == SelectionEdges.None)
+ {
+ continue;
+ }
+
+ e.Graphics.SetClip(Rectangle.Intersect(visible, e.ClipRectangle), CombineMode.Replace);
+
+ var inset = pen.Width / 2;
+ var left = bounds.Left + inset;
+ var right = bounds.Right - inset;
+ var top = bounds.Top + inset;
+ var bottom = bounds.Bottom - inset;
+ if (edges.HasFlag(SelectionEdges.Top))
+ {
+ e.Graphics.DrawLine(pen, bounds.Left, top, bounds.Right, top);
+ }
+
+ if (edges.HasFlag(SelectionEdges.Bottom))
+ {
+ e.Graphics.DrawLine(pen, bounds.Left, bottom, bounds.Right, bottom);
+ }
+
+ if (edges.HasFlag(SelectionEdges.Left))
+ {
+ e.Graphics.DrawLine(pen, left, bounds.Top, left, bounds.Bottom);
+ }
+
+ if (edges.HasFlag(SelectionEdges.Right))
+ {
+ e.Graphics.DrawLine(pen, right, bounds.Top, right, bounds.Bottom);
+ }
+ }
+ }
+ }
+ finally
+ {
+ e.Graphics.Restore(state);
+ }
+ }
+}
+
+[SupportedOSPlatform("windows")]
+internal readonly record struct SelectionCellStyle (bool FillBackground, Color Background, bool CustomColor)
+{
+ public Color Foreground (Color original) => !FillBackground ? original
+ : CustomColor ? PaintHelper.GetForeColorBasedOnBackColor(Background)
+ : original == Color.Black ? Color.White : original;
+
+ public bool PaintBackground (DataGridViewCellPaintingEventArgs e)
+ {
+ if (!FillBackground)
+ {
+ return false;
+ }
+
+ using var brush = new SolidBrush(Background);
+ e.Graphics.FillRectangle(brush, e.CellBounds);
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/LogExpert.UI/Interface/ILogPaintContextUI.cs b/src/LogExpert.UI/Interface/ILogPaintContextUI.cs
index 5c3b039b..3c11641e 100644
--- a/src/LogExpert.UI/Interface/ILogPaintContextUI.cs
+++ b/src/LogExpert.UI/Interface/ILogPaintContextUI.cs
@@ -1,4 +1,5 @@
using ColumnizerLib;
+using LogExpert.Core.Config;
using LogExpert.Core.Classes.Highlight;
using LogExpert.Core.Entities;
@@ -22,6 +23,8 @@ internal interface ILogPaintContextUI : ILogLineSource
Color BookmarkColor { get; }
+ SelectionHighlightSettings SelectionHighlight { get; }
+
#endregion
#region Public methods
@@ -37,4 +40,4 @@ internal interface ILogPaintContextUI : ILogLineSource
IList FindHighlightMatches (ITextValueMemory line);
#endregion
-}
\ No newline at end of file
+}