1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.MachineStudio.Common;
using Tango.MachineStudio.HardwareDesigner.Views;
using Tango.SharedUI.Helpers;
namespace Tango.MachineStudio.HardwareDesigner
{
[StudioModule(3)]
public class HardwareDesignerModule : StudioModuleBase
{
public override string Name
{
get
{
return "Hardware Versions";
}
}
public override string Description
{
get
{
return "Select and configure hardware versions using the available hardware components. Hardware versions can be assigned to a machine configuration using the Machine Designer module.";
}
}
public override BitmapSource Image
{
get
{
return ResourceHelper.GetImageFromResources("Images/components.png");
}
}
/// <summary>
/// Gets the module entry point view type.
/// </summary>
public override Type MainViewType
{
get
{
return typeof(MainView);
}
}
public override Permissions Permission
{
get
{
return Permissions.RunHardwareVersionsModule;
}
}
public override void pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */// 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.Linq;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
using Tango.Scripting.Editors.Document;
using Tango.Scripting.Editors.Editing;
using Tango.Scripting.Editors.Rendering;
using Tango.Scripting.Editors.Utils;
using System.ComponentModel;
namespace Tango.Scripting.Editors.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;
TextDocument document;
/// <summary>
/// Gets/Sets the start of the text range in which the completion window stays open.
/// This text portion is used to determine the text used to select an entry in the completion list by typing.
/// </summary>
public int StartOffset { get; set; }
/// <summary>
/// Gets/Sets the end of the text range in which the completion window stays open.
/// This text portion is used to determine the text used to select an entry in the completion list by typing.
/// </summary>
public int EndOffset { get; set; }
/// <summary>
/// Gets whether the window was opened above the current line.
/// </summary>
protected bool IsUp { get; private set; }
/// <summary>
/// Creates a new CompletionWindowBase.
/// </summary>
public CompletionWindowBase(TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
this.TextArea = textArea;
parentWindow = Window.GetWindow(TextArea);
this.Owner = parentWindow;
this.AddHandler(MouseUpEvent, new MouseButtonEventHandler(OnMouseUp), true);
}
public virtual void ShowCompletion()
{
StartOffset = EndOffset = this.TextArea.Caret.Offset;
AttachEvents();
SetPosition();
UpdatePosition();
Show();
}
public virtual void HideCompletion()
{
Debug.WriteLine("Hide Completion...");
DetachEvents();
Hide();
}
#region Event Handlers
void AttachEvents()
{
document = this.TextArea.Document;
if (document != null) {
document.Changing += textArea_Document_Changing;
}
// LostKeyboardFocus seems to be more reliable than PreviewLostKeyboardFocus - see SD-1729
this.TextArea.LostKeyboardFocus += TextAreaLostFocus;
this.TextArea.TextView.ScrollOffsetChanged += TextViewScrollOffsetChanged;
this.TextArea.DocumentChanged += TextAreaDocumentChanged;
if (parentWindow != null) {
parentWindow.LocationChanged += parentWindow_LocationChanged;
}
// close previous completion windows of same type
foreach (InputHandler x in this.TextArea.StackedInputHandlers.OfType<InputHandler>()) {
if (x.window.GetType() == this.GetType())
this.TextArea.PopStackedInputHandler(x);
}
myInputHandler = new InputHandler(this);
this.TextArea.PushStackedInputHandler(myInputHandler);
}
/// <summary>
/// Detaches events from the text area.
/// </summary>
protected virtual void DetachEvents()
{
if (document != null) {
document.Changing -= textArea_Document_Changing;
}
this.TextArea.LostKeyboardFocus -= TextAreaLostFocus;
this.TextArea.TextView.ScrollOffsetChanged -= TextViewScrollOffsetChanged;
this.TextArea.DocumentChanged -= TextAreaDocumentChanged;
if (parentWindow != null) {
parentWindow.LocationChanged -= parentWindow_LocationChanged;
}
this.TextArea.PopStackedInputHandler(myInputHandler);
}
#region InputHandler
InputHandler myInputHandler;
/// <summary>
/// A dummy input handler (that justs invokes the default input handler).
/// This is used to ensure the completion window closes when any other input handler
/// becomes active.
/// </summary>
sealed class InputHandler : TextAreaStackedInputHandler
{
internal readonly CompletionWindowBase window;
public InputHandler(CompletionWindowBase window)
: base(window.TextArea)
{
Debug.Assert(window != null);
this.window = window;
}
public override void Detach()
{
base.Detach();
//window.HideCompletion();
}
const Key KeyDeadCharProcessed = (Key)0xac; // Key.DeadCharProcessed; // new in .NET 4
public override void OnPreviewKeyDown(KeyEventArgs e)
{
// prevents crash when typing deadchar while CC window is open
if (e.Key == KeyDeadCharProcessed)
return;
e.Handled = RaiseEventPair(window, PreviewKeyDownEvent, KeyDownEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
public override void OnPreviewKeyUp(KeyEventArgs e)
{
if (e.Key == KeyDeadCharProcessed)
return;
e.Handled = RaiseEventPair(window, PreviewKeyUpEvent, KeyUpEvent,
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key));
}
}
#endregion
void TextViewScrollOffsetChanged(object sender, EventArgs e)
{
// Workaround for crash #1580 (reproduction steps unknown):
// NullReferenceException in System.Windows.Window.CreateSourceWindow()
if (!sourceIsInitialized)
return;
IScrollInfo scrollInfo = this.TextArea.TextView;
Rect visibleRect = new Rect(scrollInfo.HorizontalOffset, scrollInfo.VerticalOffset, scrollInfo.ViewportWidth, scrollInfo.ViewportHeight);
// close completion window when the user scrolls so far that the anchor position is leaving the visible area
if (visibleRect.Contains(visualLocation) || visibleRect.Contains(visualLocationTop))
UpdatePosition();
else
HideCompletion();
}
void TextAreaDocumentChanged(object sender, EventArgs e)
{
HideCompletion();
}
void TextAreaLostFocus(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background);
}
void parentWindow_LocationChanged(object sender, EventArgs e)
{
UpdatePosition();
}
/// <inheritdoc/>
protected override void OnDeactivated(EventArgs e)
{
base.OnDeactivated(e);
Dispatcher.BeginInvoke(new Action(CloseIfFocusLost), DispatcherPriority.Background);
}
#endregion
/// <summary>
/// Raises a tunnel/bubble event pair for a WPF control.
/// </summary>
/// <param name="target">The WPF control for which the event should be raised.</param>
/// <param name="previewEvent">The tunneling event.</param>
/// <param name="event">The bubbling event.</param>
/// <param name="args">The event args to use.</param>
/// <returns>The <see cref="RoutedEventArgs.Handled"/> value of the event args.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
protected static bool RaiseEventPair(UIElement target, RoutedEvent previewEvent, RoutedEvent @event, RoutedEventArgs args)
{
if (target == null)
throw new ArgumentNullException("target");
if (previewEvent == null)
throw new ArgumentNullException("previewEvent");
if (@event == null)
throw new ArgumentNullException("event");
if (args == null)
throw new ArgumentNullException("args");
args.RoutedEvent = previewEvent;
target.RaiseEvent(args);
args.RoutedEvent = @event;
target.RaiseEvent(args);
return args.Handled;
}
// Special handler: handledEventsToo
void OnMouseUp(object sender, MouseButtonEventArgs e)
{
ActivateParentWindow();
}
/// <summary>
/// Activates the parent window.
/// </summary>
protected virtual void ActivateParentWindow()
{
if (parentWindow != null)
parentWindow.Activate();
}
void CloseIfFocusLost()
{
if (CloseOnFocusLost) {
Debug.WriteLine("CloseIfFocusLost: this.IsActive=" + this.IsActive + " IsTextAreaFocused=" + IsTextAreaFocused);
if (!this.IsActive && !IsTextAreaFocused) {
HideCompletion();
}
}
}
/// <summary>
/// Gets whether the completion window should automatically close when the text editor looses focus.
/// </summary>
protected virtual bool CloseOnFocusLost {
get { return true; }
}
bool IsTextAreaFocused {
get {
if (parentWindow != null && !parentWindow.IsActive)
return false;
return this.TextArea.IsKeyboardFocused;
}
}
bool sourceIsInitialized;
/// <inheritdoc/>
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
SetPosition();
//sourceIsInitialized = true;
}
public void SetPosition()
{
if (document != null && this.StartOffset != this.TextArea.Caret.Offset)
{
SetPosition(new TextViewPosition(document.GetLocation(this.StartOffset)));
}
else
{
SetPosition(this.TextArea.Caret.Position);
}
}
public void UpdatePositionFix()
{
SetPosition(this.TextArea.Caret.Position);
}
//public void UpdatePosition()
//{
// SetPosition(this.TextArea.Caret.Position);
//}
/// <inheritdoc/>
protected override void OnClosed(EventArgs e)
{
DetachEvents();
HideCompletion();
}
/// <inheritdoc/>
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!e.Handled && e.Key == Key.Escape) {
e.Handled = true;
HideCompletion();
}
}
Point visualLocation, visualLocationTop;
/// <summary>
/// Positions the completion window at the specified position.
/// </summary>
protected void SetPosition(TextViewPosition position)
{
TextView textView = this.TextArea.TextView;
visualLocation = textView.GetVisualPosition(position, VisualYPosition.LineBottom);
visualLocationTop = textView.GetVisualPosition(position, VisualYPosition.LineTop);
UpdatePosition();
}
/// <summary>
/// Updates the position of the CompletionWindow based on the parent TextView position and the screen working area.
/// It ensures that the CompletionWindow is completely visible on the screen.
/// </summary>
public void UpdatePosition()
{
TextView textView = this.TextArea.TextView;
// PointToScreen returns device dependent units (physical pixels)
Point location = textView.PointToScreen(visualLocation - textView.ScrollOffset);
Point locationTop = textView.PointToScreen(visualLocationTop - textView.ScrollOffset);
// Let's use device dependent units for everything
Size completionWindowSize = new Size(this.ActualWidth, this.ActualHeight).TransformToDevice(textView);
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;
IsUp = true;
} else {
IsUp = false;
}
if (bounds.Y < workingScreen.Top) {
bounds.Y = workingScreen.Top;
}
}
// Convert the window bounds to device independent units
bounds = bounds.TransformFromDevice(textView);
this.Left = bounds.X;
this.Top = bounds.Y;
Debug.WriteLine($"Position: {Left}x{Top}");
}
/// <inheritdoc/>
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
if (sizeInfo.HeightChanged && IsUp) {
this.Top += sizeInfo.PreviousSize.Height - sizeInfo.NewSize.Height;
}
}
/// <summary>
/// Gets/sets whether the completion window should expect text insertion at the start offset,
/// which not go into the completion region, but before it.
/// </summary>
/// <remarks>This property allows only a single insertion, it is reset to false
/// when that insertion has occurred.</remarks>
public bool ExpectInsertionBeforeStart { get; set; }
void textArea_Document_Changing(object sender, DocumentChangeEventArgs e)
{
if (e.Offset + e.RemovalLength == this.StartOffset && e.RemovalLength > 0) {
HideCompletion(); // removal immediately in front of completion segment: close the window
// this is necessary when pressing backspace after dot-completion
}
if (e.Offset == StartOffset && e.RemovalLength == 0 && ExpectInsertionBeforeStart) {
StartOffset = e.GetNewOffset(StartOffset, AnchorMovementType.AfterInsertion);
this.ExpectInsertionBeforeStart = false;
} else {
StartOffset = e.GetNewOffset(StartOffset, AnchorMovementType.BeforeInsertion);
}
EndOffset = e.GetNewOffset(EndOffset, AnchorMovementType.AfterInsertion);
}
}
}
|