diff --git a/Arma.Studio.Data/ArmA.Studio.Data.csproj b/Arma.Studio.Data/ArmA.Studio.Data.csproj index 8c410cf..c48e1ec 100644 --- a/Arma.Studio.Data/ArmA.Studio.Data.csproj +++ b/Arma.Studio.Data/ArmA.Studio.Data.csproj @@ -177,6 +177,7 @@ + diff --git a/Arma.Studio.Data/UI/RelayDataTemplateSelector.cs b/Arma.Studio.Data/UI/RelayDataTemplateSelector.cs new file mode 100644 index 0000000..3e66e17 --- /dev/null +++ b/Arma.Studio.Data/UI/RelayDataTemplateSelector.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace Arma.Studio.Data.UI +{ + public class RelayDataTemplateSelector : DataTemplateSelector + { + private readonly Control RelayTo; + public RelayDataTemplateSelector(Control control) + { + this.RelayTo = control; + } + + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + var baseResult = base.SelectTemplate(item, container); + if (baseResult != null || item is null) + { + return baseResult; + } + var objType = item.GetType(); + var matches = this.RelayTo.Resources + .Cast() + .Select((it) => it.Value) + .Where((it) => it is DataTemplate) + .Cast() + .Where((it) => it.DataType is Type t && t.IsAssignableFrom(objType)).ToArray(); + if (!matches.Any()) + { + return null; + } + // ToDo: Find the best match + var template = matches.First(); + return (DataTemplate)template; + } + } +} diff --git a/Arma.Studio/ArmA.Studio.csproj b/Arma.Studio/ArmA.Studio.csproj index 7c5cfcf..55d6541 100644 --- a/Arma.Studio/ArmA.Studio.csproj +++ b/Arma.Studio/ArmA.Studio.csproj @@ -247,6 +247,11 @@ + + + PreserveNewest + + git rev-parse HEAD > "$(ProjectDir)\git-version.txt" diff --git a/Arma.Studio/Extensions.cs b/Arma.Studio/Extensions.cs index e5843f1..757b8b1 100644 --- a/Arma.Studio/Extensions.cs +++ b/Arma.Studio/Extensions.cs @@ -64,11 +64,11 @@ public static int GetStartOffset(this TextEditor editor) /// A valid instance. /// The method to be used to test the characters. Should return True unless the char is not valid. /// - public static int GetStartOffset(this TextEditor editor, Func isSeparatorCharacter = null) + public static int GetStartOffsetByCaret(this TextEditor editor, Func isSeparatorCharacter = null) { if (isSeparatorCharacter == null) { - isSeparatorCharacter = Char.IsLetter; + isSeparatorCharacter = (c) => !Char.IsLetter(c); } int off = editor.CaretOffset; if (off <= 0 || off > editor.Document.TextLength) @@ -91,6 +91,71 @@ public static int GetStartOffset(this TextEditor editor, Func isSepa } return 0; } + /// + /// Tries to find the start of a word. + /// + /// A valid instance. + /// The method to be used to test the characters. Should return True unless the char is not valid. + /// + public static int GetStartOffset(this TextDocument document, int baseOffset, Func isSeparatorCharacter = null) + { + if (isSeparatorCharacter == null) + { + isSeparatorCharacter = (c) => !Char.IsLetter(c); + } + int off = baseOffset; + if (off <= 0 || off > document.TextLength) + { + return off; + } + + + int start; + + // find start + for (start = off - 1; start >= 0; start--) + { + char c = document.GetCharAt(start); + if (isSeparatorCharacter(c)) + { + start++; + return start; + } + } + return -1; + } + /// + /// Tries to find the start of a word. + /// + /// A valid instance. + /// The method to be used to test the characters. Should return True unless the char is not valid. + /// + public static int GetEndOffset(this TextDocument document, int baseOffset, Func isSeparatorCharacter = null) + { + if (isSeparatorCharacter == null) + { + isSeparatorCharacter = (c) => !Char.IsLetter(c); + } + int off = baseOffset; + if (off <= 0 || off > document.TextLength) + { + return off; + } + + + int start; + + // find start + for (start = off; start < document.TextLength; start++) + { + char c = document.GetCharAt(start); + if (isSeparatorCharacter(c)) + { + return start; + } + } + return -1; + } } } diff --git a/Arma.Studio/UI/TextEditor.xaml b/Arma.Studio/UI/TextEditor.xaml index bfb71ba..116b532 100644 --- a/Arma.Studio/UI/TextEditor.xaml +++ b/Arma.Studio/UI/TextEditor.xaml @@ -15,6 +15,23 @@ IsReadOnly="{Binding IsReadOnly}" FontFamily="Consolas" asd:AttachedDataContext.DataContext="{Binding}"> - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Arma.Studio/UI/TextEditorDataContext.cs b/Arma.Studio/UI/TextEditorDataContext.cs index af2c637..aaa366b 100644 --- a/Arma.Studio/UI/TextEditorDataContext.cs +++ b/Arma.Studio/UI/TextEditorDataContext.cs @@ -439,10 +439,65 @@ public void OnInitialized(FrameworkElement sender, EventArgs e) this.FoldingManager = ICSharpCode.AvalonEdit.Folding.FoldingManager.Install(textEditor.TextArea); textEditor.TextArea.TextEntering += this.TextArea_TextEntering; - textEditor.TextArea.TextEntered += this.TextArea_TextEntered; ; + textEditor.TextArea.TextEntered += this.TextArea_TextEntered; + textEditor.MouseHover += this.TextEditor_MouseHover; + textEditor.MouseHoverStopped += this.TextEditor_MouseHoverStopped; } } + + public ToolTip ToolTip + { + get + { + if (this._ToolTip is null) + { + this._ToolTip = new ToolTip + { + PlacementTarget = this.TextEditorControl, + Placement = PlacementMode.MousePoint, + ContentTemplateSelector = new RelayDataTemplateSelector(this.TextEditorControl) + }; + } + this._ToolTip.IsOpen = true; + return this._ToolTip; + } + } + private ToolTip _ToolTip; + private void TextEditor_MouseHover(object sender, MouseEventArgs e) + { + var relativePosition = e.GetPosition(this.TextEditorControl); + var textPosition = this.TextEditorControl.GetPositionFromPoint(relativePosition); + if (textPosition is null) + { + return; + } + var offset = this.TextDocument.GetOffset(textPosition.Value.Line, textPosition.Value.Column); + int start, end; + if (this.TextEditorInstance is ICodeCompletable codeCompletable) + { + start = this.TextDocument.GetStartOffset(offset, codeCompletable.IsSeparatorCharacter); + end = this.TextDocument.GetEndOffset(offset, codeCompletable.IsSeparatorCharacter); + } + else + { + start = this.TextDocument.GetStartOffset(offset); + end = this.TextDocument.GetEndOffset(offset); + } + var word = this.TextDocument.GetText(start, end - start); + start = this.TextDocument.GetLocation(start).Column - 1; + end = this.TextDocument.GetLocation(end).Column; + var lintInfo = this.GetLintInfos().Where((it) => it.Line == textPosition.Value.Line && start <= it.Column && it.Column <= end).FirstOrDefault(); + if (lintInfo != null) + { + this.ToolTip.Content = lintInfo; + } + } + private void TextEditor_MouseHoverStopped(object sender, MouseEventArgs e) + { + this.ToolTip.IsOpen = false; + } + private void TextArea_TextEntered(object sender, TextCompositionEventArgs e) { this.ShowAutoCompletion(); @@ -571,11 +626,11 @@ private void ShowAutoCompletion() this.CompletionWindow.Closed += delegate { this.CompletionWindow = null; }; - this.CompletionWindow.StartOffset = this.TextEditorControl.GetStartOffset(codeCompletable.IsSeparatorCharacter); + this.CompletionWindow.StartOffset = this.TextEditorControl.GetStartOffsetByCaret(codeCompletable.IsSeparatorCharacter); this.CompletionWindow.EndOffset = this.TextEditorControl.CaretOffset; this.CompletionWindow.Show(); } - this.CompletionWindow.StartOffset = this.TextEditorControl.GetStartOffset(codeCompletable.IsSeparatorCharacter); + this.CompletionWindow.StartOffset = this.TextEditorControl.GetStartOffsetByCaret(codeCompletable.IsSeparatorCharacter); var data = this.CompletionWindow.CompletionList.CompletionData; data.Clear(); data.AddRange(codeCompletable.GetAutoCompleteInfos(this.TextDocument.Text, this.TextEditorControl.CaretOffset).Select((it) => new CompletionData(it))); diff --git a/Arma.Studio/UI/UnderlineBackgroundRenderer.cs b/Arma.Studio/UI/UnderlineBackgroundRenderer.cs index 03478f0..83f0f8c 100644 --- a/Arma.Studio/UI/UnderlineBackgroundRenderer.cs +++ b/Arma.Studio/UI/UnderlineBackgroundRenderer.cs @@ -60,7 +60,6 @@ private IEnumerable GetPoints(Rect rect, double offset, int count) } } - public void Draw(TextView textView, DrawingContext drawingContext) { textView.EnsureVisualLines();