-
Notifications
You must be signed in to change notification settings - Fork 53
RichEditBoxFormatter addition for ColorCode.UWP #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| using Windows.UI.Xaml; | ||
| using Windows.UI.Xaml.Controls; | ||
| using Windows.UI.Xaml.Media; | ||
|
|
||
| namespace ColorCode.Common | ||
| { | ||
| public static class VisualHelpers | ||
| { | ||
| /// <summary> | ||
| /// Commandbars causing crashes at the mo | ||
| /// </summary> | ||
| /// <typeparam name="T"></typeparam> | ||
| /// <param name="parent"></param> | ||
| /// <param name="deepscan"></param> | ||
| /// <param name="includeCommandBars"></param> | ||
| /// <returns></returns> | ||
| public static T FirstChildofType<T>(DependencyObject parent, bool deepscan = false, bool includeCommandBars = false) | ||
| { | ||
| if (parent == null) return (T)(object)null; | ||
| if (deepscan) | ||
| { | ||
| if (parent is ContentPresenter presenter) | ||
| { | ||
| var _Child = presenter.Content as DependencyObject; | ||
| if (_Child is T) | ||
| { | ||
| return (T)(object)_Child; | ||
| } | ||
| if (!(_Child is CommandBar) || includeCommandBars) | ||
| { | ||
| var next = (FirstChildofType<T>(_Child, deepscan)); | ||
| if (next is T) | ||
| { | ||
| return ((T)(object)next); | ||
| } | ||
| } | ||
| } | ||
| else if (parent is ContentControl control) | ||
| { | ||
| var _Child = control.Content as DependencyObject; | ||
| if (_Child is T) | ||
| { | ||
| return (T)(object)_Child; | ||
| } | ||
| if (!(_Child is CommandBar) || includeCommandBars) | ||
| { | ||
| var next = (FirstChildofType<T>(_Child, deepscan)); | ||
| if (next is T) | ||
| { | ||
| return ((T)(object)next); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) | ||
| { | ||
| var _Child = VisualTreeHelper.GetChild(parent, i); | ||
| if (_Child is T) | ||
| { | ||
| return ((T)(object)_Child); | ||
| } | ||
| if (!(_Child is CommandBar) || includeCommandBars) | ||
| { | ||
| var next = (FirstChildofType<T>(_Child, deepscan)); | ||
| if (next is T) | ||
| { | ||
| return ((T)(object)next); | ||
| } | ||
| } | ||
| } | ||
| return (T)(object)null; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| using System.Collections.Generic; | ||
| using ColorCode.Parsing; | ||
| using Windows.UI.Xaml.Controls; | ||
| using ColorCode.Styling; | ||
| using Windows.UI.Text; | ||
| using ColorCode.UWP.Common; | ||
| using ColorCode.Common; | ||
| using Windows.UI.Xaml; | ||
| using System.Text.RegularExpressions; | ||
|
|
||
| namespace ColorCode | ||
| { | ||
| /// <summary> | ||
| /// Creates a <see cref="RichTextBlockFormatter"/>, for rendering Syntax Highlighted code to a RichTextBlock. | ||
| /// </summary> | ||
| public class RichEditBoxFormatter : CodeColorizerBase | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like this could this be an extension with an attached property instead of a helper class?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could be both, I would like to keep the formatter class style, as that is what the other Formatters are. I haven't played with extensions before, but I'll look into it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would I set a Markup Extension for a specific control only, is there some documentation on creating UI Extensions for more info than I can garner from the ones in the Toolkit?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You just change the type in the Get/SetValue from DependencyProperty to the specific control to limit it (like they did in TextBoxRegEx). Is that what you're asking? |
||
| { | ||
| /// <summary> | ||
| /// Creates a <see cref="RichTextBlockFormatter"/>, for rendering Syntax Highlighted code to a RichTextBlock. | ||
| /// </summary> | ||
| /// <param name="Theme">The Theme to use, determines whether to use Default Light or Default Dark.</param> | ||
| public RichEditBoxFormatter(ElementTheme Theme, ILanguageParser languageParser = null) : this(Theme == ElementTheme.Dark ? StyleDictionary.DefaultDark : StyleDictionary.DefaultLight, languageParser) | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a <see cref="RichTextBlockFormatter"/>, for rendering Syntax Highlighted code to a RichTextBlock. | ||
| /// </summary> | ||
| /// <param name="Style">The Custom styles to Apply to the formatted Code.</param> | ||
| /// <param name="languageParser">The language parser that the <see cref="RichTextBlockFormatter"/> instance will use for its lifetime.</param> | ||
| public RichEditBoxFormatter(StyleDictionary Style = null, ILanguageParser languageParser = null) : base(Style, languageParser) | ||
| { | ||
| } | ||
|
|
||
| private RichEditBox RichEdit { get; set; } | ||
|
|
||
| public ILanguage Language | ||
| { | ||
| get => _Language; | ||
| set | ||
| { | ||
| _Language = value; | ||
| UpdateText(); | ||
| } | ||
| } | ||
|
|
||
| private ILanguage _Language; | ||
|
|
||
| /// <summary> | ||
| /// Adds Syntax Highlighted Source Code to the provided RichTextBlock. | ||
| /// </summary> | ||
| /// <param name="sourceCode">The source code to colorize.</param> | ||
| /// <param name="language">The language to use to colorize the source code.</param> | ||
| /// <param name="RichEdit">The Control to add the Text to.</param> | ||
| public void AttachRichEditBox(RichEditBox RichEdit, ILanguage Language) | ||
| { | ||
| this.RichEdit = RichEdit; | ||
| RichEdit.TextChanging += RichEdit_TextChanging; | ||
| this.Language = Language; | ||
| } | ||
|
|
||
| private void RichEdit_TextChanging(RichEditBox sender, RichEditBoxTextChangingEventArgs args) | ||
| { | ||
| if (args.IsContentChanging) | ||
| { | ||
| UpdateText(); | ||
| } | ||
| } | ||
|
|
||
| public void UpdateText() | ||
| { | ||
| if (RichEdit != null) | ||
| { | ||
| // Attempt to get Scrollviewer offsets, to preserve location. | ||
| var scroll = VisualHelpers.FirstChildofType<ScrollViewer>(RichEdit); | ||
| var vertOffset = scroll?.VerticalOffset; | ||
| var horOffset = scroll?.HorizontalOffset; | ||
|
|
||
| var selection = RichEdit.Document.Selection; | ||
| var selectionStart = selection.StartPosition; | ||
| var selectionEnd = selection.EndPosition; | ||
|
|
||
| RichEdit.Document.GetText(TextGetOptions.UseCrlf, out string raw); | ||
| RichEdit.Document.Undo(); | ||
|
|
||
| RichEdit.Document.BeginUndoGroup(); | ||
| RichEdit.Document.SetText(TextSetOptions.None, raw); | ||
|
|
||
| var newSelection = RichEdit.Document.Selection; | ||
| newSelection.StartPosition = selectionStart; | ||
| newSelection.EndPosition = selectionEnd; | ||
|
|
||
| Index = 0; | ||
| source = raw; | ||
|
|
||
| languageParser.Parse(raw, Language, (range, captures) => Style(range, captures)); | ||
| RichEdit.Document.ApplyDisplayUpdates(); | ||
| RichEdit.Document.EndUndoGroup(); | ||
|
|
||
| if (scroll != null) | ||
| { | ||
| scroll.ChangeView(horOffset, vertOffset, null, true); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private static int Index = 0; | ||
| private static string source = string.Empty; | ||
|
|
||
| protected void Style(string range, IList<Scope> scopes) | ||
| { | ||
| var scopeRange = source.Substring(Index); | ||
|
|
||
| var start = Index; | ||
|
|
||
| try | ||
| { | ||
| var previous = source.Remove(Index); | ||
| var crlfCorrection = CountOccurences(previous, "\r\n"); | ||
| start -= crlfCorrection; | ||
| } | ||
| catch | ||
| { | ||
| } | ||
|
|
||
| var subIndex = scopeRange.IndexOf(range); | ||
| if (subIndex != -1) | ||
| { | ||
| start += subIndex; | ||
| } | ||
|
|
||
| foreach (var scope in scopes) | ||
| { | ||
| StyleFromScope(start, scope); | ||
| } | ||
|
|
||
| Index += range.Length; | ||
| } | ||
|
|
||
| private int CountOccurences(string str, string match) | ||
| { | ||
| return Regex.Matches(str, match).Count; | ||
| } | ||
|
|
||
| private void StyleFromScope(int Start, Scope Scope) | ||
| { | ||
| Start += Scope.Index; | ||
| var Range = RichEdit.Document.GetRange(Start, Start + Scope.Length); | ||
|
|
||
| string foreground = null; | ||
| string background = null; | ||
| bool italic = false; | ||
| bool bold = false; | ||
|
|
||
| if (Styles.Contains(Scope.Name)) | ||
| { | ||
| Styling.Style style = Styles[Scope.Name]; | ||
|
|
||
| foreground = style.Foreground; | ||
| background = style.Background; | ||
| italic = style.Italic; | ||
| bold = style.Bold; | ||
| } | ||
|
|
||
| if (!string.IsNullOrWhiteSpace(foreground)) | ||
| { | ||
| Range.CharacterFormat.ForegroundColor = foreground.GetColor(); | ||
| } | ||
|
|
||
| if (!string.IsNullOrWhiteSpace(background)) | ||
| { | ||
| Range.CharacterFormat.BackgroundColor = background.GetColor(); | ||
| } | ||
|
|
||
| if (italic) | ||
| Range.CharacterFormat.Italic = FormatEffect.On; | ||
|
|
||
| if (bold) | ||
| Range.CharacterFormat.Bold = FormatEffect.On; | ||
|
|
||
| foreach (var subScope in Scope.Children) | ||
| { | ||
| StyleFromScope(Start, subScope); | ||
| } | ||
| } | ||
|
|
||
| private void Reset(ITextRange Range) | ||
| { | ||
| var defaults = RichEdit.Document.GetDefaultCharacterFormat(); | ||
| Range.CharacterFormat.Italic = FormatEffect.Off; | ||
| Range.CharacterFormat.Bold = FormatEffect.Off; | ||
| Range.CharacterFormat.BackgroundColor = defaults.BackgroundColor; | ||
| Range.CharacterFormat.ForegroundColor = defaults.ForegroundColor; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like just a combo of the LogicalTree Helpers and the VisualTree Helpers already in the toolkit, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't see any in the toolkit? Point me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/Microsoft/UWPCommunityToolkit/blob/master/Microsoft.Toolkit.Uwp.UI/Extensions/Tree/LogicalTree.cs