Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3873 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
18 changed files with 454 additions and 35 deletions
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Windows.Controls; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.CodeCompletion |
||||
{ |
||||
/// <summary>
|
||||
/// The listbox used inside the CompletionWindow.
|
||||
/// </summary>
|
||||
public class CompletionList : ListBox |
||||
{ |
||||
|
||||
} |
||||
} |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
<cc:CompletionWindowBase |
||||
x:Class="ICSharpCode.AvalonEdit.CodeCompletion.CompletionWindow" |
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
xmlns:cc="clr-namespace:ICSharpCode.AvalonEdit.CodeCompletion" |
||||
Height="300" Width="200" |
||||
> |
||||
<cc:CompletionList/> |
||||
</cc:CompletionWindowBase> |
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
using ICSharpCode.AvalonEdit.Document; |
||||
using System; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.CodeCompletion |
||||
{ |
||||
/// <summary>
|
||||
/// The code completion window.
|
||||
/// </summary>
|
||||
public partial class CompletionWindow : CompletionWindowBase |
||||
{ |
||||
TextDocument document; |
||||
int startOffset; |
||||
int endOffset; |
||||
|
||||
/// <summary>
|
||||
/// Creates a new code completion window.
|
||||
/// </summary>
|
||||
public CompletionWindow(TextArea textArea) : base(textArea) |
||||
{ |
||||
InitializeComponent(); |
||||
|
||||
document = textArea.TextView.Document; |
||||
startOffset = endOffset = textArea.Caret.Offset; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void AttachEvents() |
||||
{ |
||||
base.AttachEvents(); |
||||
document.Changing += textArea_Document_Changing; |
||||
this.TextArea.Caret.PositionChanged += CaretPositionChanged; |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void DetachEvents() |
||||
{ |
||||
document.Changing -= textArea_Document_Changing; |
||||
this.TextArea.Caret.PositionChanged -= CaretPositionChanged; |
||||
base.DetachEvents(); |
||||
} |
||||
|
||||
void textArea_Document_Changing(object sender, DocumentChangeEventArgs e) |
||||
{ |
||||
// => startOffset test required so that this startOffset/endOffset are not incremented again
|
||||
// for BeforeStartKey characters
|
||||
if (e.Offset >= startOffset && e.Offset <= endOffset) { |
||||
endOffset += e.InsertionLength - e.RemovalLength; |
||||
} else { |
||||
Close(); |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// When this flag is set, code completion closes if the caret moves to the
|
||||
/// beginning of the allowed range. This is useful in Ctrl+Space and "complete when typing",
|
||||
/// but not in dot-completion.
|
||||
/// </summary>
|
||||
public bool CloseWhenCaretAtBeginning { get; set; } |
||||
|
||||
void CaretPositionChanged(object sender, EventArgs e) |
||||
{ |
||||
int offset = this.TextArea.Caret.Offset; |
||||
if (offset == startOffset) { |
||||
if (CloseWhenCaretAtBeginning) |
||||
Close(); |
||||
return; |
||||
} |
||||
if (offset < startOffset || offset > endOffset) { |
||||
Close(); |
||||
} else { |
||||
//codeCompletionListView.SelectItemWithStart(document.GetText(startOffset, offset - startOffset));
|
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,178 @@
@@ -0,0 +1,178 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using System.Windows; |
||||
using System.Windows.Input; |
||||
using System.Windows.Threading; |
||||
|
||||
using ICSharpCode.AvalonEdit.Gui; |
||||
using ICSharpCode.AvalonEdit.Utils; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.CodeCompletion |
||||
{ |
||||
/// <summary>
|
||||
/// Base class for completion windows. Handles positioning the window at the caret.
|
||||
/// </summary>
|
||||
public class CompletionWindowBase : Window |
||||
{ |
||||
static CompletionWindowBase() |
||||
{ |
||||
WindowStyleProperty.OverrideMetadata(typeof(CompletionWindowBase), new FrameworkPropertyMetadata(WindowStyle.None)); |
||||
ShowActivatedProperty.OverrideMetadata(typeof(CompletionWindowBase), new FrameworkPropertyMetadata(Boxes.False)); |
||||
ShowInTaskbarProperty.OverrideMetadata(typeof(CompletionWindowBase), new FrameworkPropertyMetadata(Boxes.False)); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the parent TextArea.
|
||||
/// </summary>
|
||||
public TextArea TextArea { get; private set; } |
||||
|
||||
Window parentWindow; |
||||
|
||||
/// <summary>
|
||||
/// Creates a new CompletionWindowBase.
|
||||
/// </summary>
|
||||
public CompletionWindowBase(TextArea textArea) |
||||
{ |
||||
if (textArea == null) |
||||
throw new ArgumentNullException("textArea"); |
||||
this.TextArea = textArea; |
||||
parentWindow = Window.GetWindow(textArea); |
||||
} |
||||
|
||||
#region Event Handlers
|
||||
/// <summary>
|
||||
/// Attaches events to the text area.
|
||||
/// </summary>
|
||||
protected virtual void AttachEvents() |
||||
{ |
||||
this.TextArea.LostFocus += TextAreaLostFocus; |
||||
this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged; |
||||
this.TextArea.TextView.DocumentChanged += TextViewDocumentChanged; |
||||
if (parentWindow != null) { |
||||
parentWindow.LocationChanged += parentWindow_LocationChanged; |
||||
parentWindow.Deactivated += parentWindowDeactivated; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Detaches events from the text area.
|
||||
/// </summary>
|
||||
protected virtual void DetachEvents() |
||||
{ |
||||
this.TextArea.LostFocus -= TextAreaLostFocus; |
||||
this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged; |
||||
this.TextArea.TextView.DocumentChanged -= TextViewDocumentChanged; |
||||
if (parentWindow != null) { |
||||
parentWindow.LocationChanged -= parentWindow_LocationChanged; |
||||
parentWindow.Deactivated -= parentWindowDeactivated; |
||||
} |
||||
} |
||||
|
||||
void TextViewScrollOffsetChanged(object sender, EventArgs e) |
||||
{ |
||||
UpdatePosition(); |
||||
} |
||||
|
||||
void TextViewDocumentChanged(object sender, EventArgs e) |
||||
{ |
||||
Close(); |
||||
} |
||||
|
||||
void TextAreaLostFocus(object sender, RoutedEventArgs e) |
||||
{ |
||||
Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background); |
||||
} |
||||
|
||||
void parentWindow_LocationChanged(object sender, EventArgs e) |
||||
{ |
||||
UpdatePosition(); |
||||
} |
||||
|
||||
void parentWindowDeactivated(object sender, EventArgs e) |
||||
{ |
||||
Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnDeactivated(EventArgs e) |
||||
{ |
||||
base.OnDeactivated(e); |
||||
Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background); |
||||
} |
||||
#endregion
|
||||
|
||||
void CloseIfFocusLost() |
||||
{ |
||||
Debug.WriteLine("CloseIfFocusLost"); |
||||
if (!this.IsActive && parentWindow != null && !parentWindow.IsActive) { |
||||
// close if parent window looses focus
|
||||
Close(); |
||||
} |
||||
if (!this.TextArea.IsFocused) { |
||||
Close(); |
||||
} |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnSourceInitialized(EventArgs e) |
||||
{ |
||||
base.OnSourceInitialized(e); |
||||
SetPosition(); |
||||
AttachEvents(); |
||||
} |
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnClosed(EventArgs e) |
||||
{ |
||||
base.OnClosed(e); |
||||
DetachEvents(); |
||||
} |
||||
|
||||
Point visualLocation, visualLocationTop; |
||||
|
||||
/// <summary>
|
||||
/// Positions the completion window at the caret position.
|
||||
/// </summary>
|
||||
void SetPosition() |
||||
{ |
||||
TextView textView = this.TextArea.TextView; |
||||
|
||||
visualLocation = textView.GetVisualPosition(this.TextArea.Caret.Position, VisualYPosition.LineBottom); |
||||
visualLocationTop = textView.GetVisualPosition(this.TextArea.Caret.Position, VisualYPosition.LineTop); |
||||
UpdatePosition(); |
||||
} |
||||
|
||||
void UpdatePosition() |
||||
{ |
||||
TextView textView = this.TextArea.TextView; |
||||
Point location = textView.PointToScreen(visualLocation - textView.ScrollOffset); |
||||
Point locationTop = textView.PointToScreen(visualLocationTop - textView.ScrollOffset); |
||||
|
||||
Size completionWindowSize = new Size(this.ActualWidth, this.ActualHeight); |
||||
Rect bounds = new Rect(location, completionWindowSize); |
||||
Rect workingScreen = System.Windows.Forms.Screen.GetWorkingArea(location.ToSystemDrawing()).ToWpf(); |
||||
if (!workingScreen.Contains(bounds)) { |
||||
if (bounds.Left < workingScreen.Left) { |
||||
bounds.X = workingScreen.Left; |
||||
} else if (bounds.Right > workingScreen.Right) { |
||||
bounds.X = workingScreen.Right - bounds.Width; |
||||
} |
||||
if (bounds.Bottom > workingScreen.Bottom) { |
||||
bounds.Y = locationTop.Y - bounds.Height; |
||||
} |
||||
if (bounds.Y < workingScreen.Top) { |
||||
bounds.Y = workingScreen.Top; |
||||
} |
||||
} |
||||
this.Left = bounds.X; |
||||
this.Top = bounds.Y; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <author name="Daniel Grunwald"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.Gui |
||||
{ |
||||
/// <summary>
|
||||
/// An enum that specifies the possible Y positions that can be returned by VisualLine.GetVisualPosition.
|
||||
/// </summary>
|
||||
public enum VisualYPosition |
||||
{ |
||||
/// <summary>
|
||||
/// Returns the top of the TextLine.
|
||||
/// </summary>
|
||||
LineTop, |
||||
/// <summary>
|
||||
/// Returns the top of the text. If the line contains inline UI elements larger than the text, TextTop
|
||||
/// will be below LineTop.
|
||||
/// </summary>
|
||||
TextTop, |
||||
/// <summary>
|
||||
/// Returns the bottom of the TextLine. This is the same as the bottom of the text (the text is always
|
||||
/// aligned at the bottom border).
|
||||
/// </summary>
|
||||
LineBottom, |
||||
/// <summary>
|
||||
/// The middle between LineTop and LineBottom.
|
||||
/// </summary>
|
||||
LineMiddle |
||||
} |
||||
} |
Loading…
Reference in new issue