// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using Tango.Scripting.Editors.Document;
using Tango.Scripting.Editors.Editing;
using System.Windows.Media;
namespace Tango.Scripting.Editors.CodeCompletion
{
///
/// The code completion window.
///
public class CompletionWindow : CompletionWindowBase
{
readonly CompletionList completionList = new CompletionList();
public event Action InsertionRequest;
///
/// Gets the completion list used in this completion window.
///
public CompletionList CompletionList
{
get { return completionList; }
}
///
/// Creates a new code completion window.
///
public CompletionWindow(TextArea textArea) : base(textArea)
{
// keep height automatic
this.CloseAutomatically = true;
this.SizeToContent = SizeToContent.WidthAndHeight;
this.WindowStyle = WindowStyle.None;
this.ResizeMode = ResizeMode.NoResize;
this.Content = completionList;
// prevent user from resizing window to 0x0
this.MinHeight = 15;
this.MinWidth = 30;
//this.Background = new SolidColorBrush(Color.FromRgb(15, 15, 15));
this.Foreground = Brushes.Gainsboro;
}
public override void ShowCompletion()
{
base.ShowCompletion();
AttachEvents();
}
public override void HideCompletion()
{
base.HideCompletion();
foreach (var item in completionList.ListBox.Items)
{
var box = completionList.ListBox.ItemContainerGenerator.ContainerFromItem(item) as CompletionListBoxItem;
if (box != null && box.IsSelected)
{
box.toolTip.IsOpen = false;
}
}
}
void completionList_InsertionRequested(object sender, EventArgs e)
{
HideCompletion();
// The window must close before Complete() is called.
// If the Complete callback pushes stacked input handlers, we don't want to pop those when the CC window closes.
var item = completionList.SelectedItem;
//if (item != null)
// item.Complete(this.TextArea, new AnchorSegment(this.TextArea.Document, this.StartOffset, this.EndOffset - this.StartOffset), e);
if (item != null)
{
InsertionRequest?.Invoke(item);
}
completionList.SelectedItem = null;
}
void AttachEvents()
{
this.completionList.InsertionRequested += completionList_InsertionRequested;
this.TextArea.Caret.PositionChanged += CaretPositionChanged;
this.TextArea.MouseWheel += textArea_MouseWheel;
this.TextArea.PreviewTextInput += textArea_PreviewTextInput;
}
///
protected override void DetachEvents()
{
this.completionList.InsertionRequested -= completionList_InsertionRequested;
this.TextArea.Caret.PositionChanged -= CaretPositionChanged;
this.TextArea.MouseWheel -= textArea_MouseWheel;
this.TextArea.PreviewTextInput -= textArea_PreviewTextInput;
base.DetachEvents();
}
///
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!e.Handled)
{
completionList.HandleKey(e);
}
}
void textArea_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
e.Handled = RaiseEventPair(this, PreviewTextInputEvent, TextInputEvent,
new TextCompositionEventArgs(e.Device, e.TextComposition));
if (e.Text == " ")
{
HideCompletion();
}
}
void textArea_MouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = RaiseEventPair(GetScrollEventTarget(),
PreviewMouseWheelEvent, MouseWheelEvent,
new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta));
}
UIElement GetScrollEventTarget()
{
if (completionList == null)
return this;
return completionList.ScrollViewer ?? completionList.ListBox ?? (UIElement)completionList;
}
///
/// Gets/Sets whether the completion window should close automatically.
/// The default value is true.
///
public bool CloseAutomatically { get; set; }
///
protected override bool CloseOnFocusLost
{
get { return this.CloseAutomatically; }
}
///
/// 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.
/// Has no effect if CloseAutomatically is false.
///
public bool CloseWhenCaretAtBeginning { get; set; }
void CaretPositionChanged(object sender, EventArgs e)
{
int offset = this.TextArea.Caret.Offset;
if (offset == this.StartOffset)
{
if (CloseAutomatically && CloseWhenCaretAtBeginning)
{
HideCompletion();
}
else
{
completionList.SelectItem(string.Empty);
}
return;
}
if (offset < this.StartOffset || offset > this.EndOffset)
{
if (CloseAutomatically)
{
HideCompletion();
}
}
else
{
TextDocument document = this.TextArea.Document;
if (document != null)
{
completionList.SelectItem(document.GetText(this.StartOffset, offset - this.StartOffset));
}
}
}
}
}