private bool TryUpdateVisualElementsOnThemeChanged(Brainf_ckTheme theme) { if (_SelectionHighlightBorder is null) { return(false); } UpdateVisualElementsOnThemeChanged(theme); return(true); }
private void UpdateVisualElementsOnThemeChanged(Brainf_ckTheme theme) { switch (theme.LineHighlightStyle) { case LineHighlightStyle.Outline: _SelectionHighlightBorder !.BorderThickness = new Thickness(2); _SelectionHighlightBorder.BorderBrush = new SolidColorBrush(theme.LineHighlightColor); _SelectionHighlightBorder.Background = null; break; case LineHighlightStyle.Fill: _SelectionHighlightBorder !.BorderThickness = default; _SelectionHighlightBorder.BorderBrush = null; _SelectionHighlightBorder.Background = new SolidColorBrush(theme.LineHighlightColor); break; default: ThrowHelper.ThrowArgumentException("Invalid line highlight style"); break; } }
/// <summary> /// Updates the UI when <see cref="SourceProperty"/> changes /// </summary> /// <param name="d">The source <see cref="DependencyObject"/> instance</param> /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> info for the current update</param> private static void OnSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Unpack the arguments Span @this = (Span)d; string oldValue = (string)e.OldValue, newValue = (string)e.NewValue; // Skip if the input code is empty if (string.IsNullOrEmpty(newValue)) { @this.Inlines.Clear(); return; } // When the new value is a prefix of the previous value, // it means that the user has deleted one or more characters // from the previous string. In this case we just need to traverse // the current inlines collection backwards and remove as many // runs or characters as needed. This will avoid having to recompute // the entire syntax highlight from scratch for the new text. if (oldValue.Length > newValue.Length && oldValue.StartsWith(newValue)) { // The difference is doubled because each character has an additional // zero width space character next to it, for better line wrapping int difference = (oldValue.Length - newValue.Length) * 2; do { // Get the last inline, remove it entirely if needed Run run = (Run)@this.Inlines.LastOrDefault(); if (run.Text.Length <= difference) { @this.Inlines.RemoveLast(); difference -= run.Text.Length; } else { // Inline too long, only remove the exceeding characters run.Text = run.Text.Substring(0, run.Text.Length - difference); break; } } while (difference > 0); return; } // Reuse the existing inlines when the new code is an extension of the previous code int start = 0, end = newValue.Length; if (newValue.Length > oldValue.Length && newValue.StartsWith(oldValue)) { // Move the initial offset ahead to skip the prefix characters. // Using a moving starting index saves an entire substring creation. start = oldValue.Length; if (@this.Inlines.LastOrDefault() is Run run) { // Check how many characters can be inserted into the last existing run int i = start; while (i < end && Brainf_ckTheme.HaveSameColor(run.Text[0], newValue[i])) { i++; } // If the entire prefix fit in the last run, just concat the string if (i == end) { run.Text += newValue.AsSpan(start, end - start).InterleaveWithCharacter(ZeroWidthSpace); return; } // If at least one character has been moved, insert those if (i > start) { run.Text += newValue.AsSpan(start, i).InterleaveWithCharacter(ZeroWidthSpace); } } } else { @this.Inlines.Clear(); } Brainf_ckTheme theme = SettingsService.GetValue <IdeTheme>(SettingsKeys.IdeTheme).AsBrainf_ckTheme(); // Parse and render the remaining text with new runs while (start < end) { char c = newValue[start]; int i = start + 1; // Aggregate as many characters as possible into a single run while (i < end && Brainf_ckTheme.HaveSameColor(c, newValue[i])) { i++; } // Create and display the new run @this.Inlines.Add(new Run { Text = newValue.AsSpan(start, i - start).InterleaveWithCharacter(ZeroWidthSpace), Foreground = theme.GetBrush(c) }); start = i; } }