Browse Source
Move ChangeMarkerMargin and related classes into own folder. Remove C#-specific hack from HiddenDefinitionRenderer. Do not return null from CreateHighlighter().newNRvisualizers
45 changed files with 519 additions and 418 deletions
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
// 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 ICSharpCode.Core; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn |
||||
{ |
||||
public interface IChangeWatcher : IDisposable |
||||
{ |
||||
event EventHandler ChangeOccurred; |
||||
|
||||
/// <summary>
|
||||
/// Returns the change information for a given line.
|
||||
/// Pass 0 to get the changes before the first line.
|
||||
/// </summary>
|
||||
LineChangeInfo GetChange(int lineNumber); |
||||
void Initialize(IDocument document, FileName fileName); |
||||
string GetOldVersionFromLine(int lineNumber, out int newStartLine, out bool added); |
||||
bool GetNewVersionFromLine(int lineNumber, out int offset, out int length); |
||||
IDocument CurrentDocument { get; } |
||||
IDocument BaseDocument { get; } |
||||
} |
||||
} |
@ -1,75 +0,0 @@
@@ -1,75 +0,0 @@
|
||||
// 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.Windows.Controls.Primitives; |
||||
using System.Windows.Input; |
||||
using System.Windows.Media; |
||||
|
||||
using ICSharpCode.Core.Presentation; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn.ContextActions |
||||
{ |
||||
/// <summary>
|
||||
/// Description of ContextActionsPopupBase.
|
||||
/// </summary>
|
||||
public abstract class ContextActionsPopupBase : ExtendedPopup |
||||
{ |
||||
protected ContextActionsPopupBase() |
||||
{ |
||||
this.KeyDown += OnKeyDown; |
||||
this.UseLayoutRounding = true; |
||||
TextOptions.SetTextFormattingMode(this, TextFormattingMode.Display); |
||||
} |
||||
|
||||
void OnKeyDown(object sender, KeyEventArgs e) |
||||
{ |
||||
if (e.Key == Key.Escape) |
||||
Close(); |
||||
} |
||||
|
||||
public void Open() |
||||
{ |
||||
this.IsOpen = true; |
||||
} |
||||
|
||||
public void Close() |
||||
{ |
||||
this.IsOpen = false; |
||||
} |
||||
|
||||
protected void OpenAtPosition(ITextEditor editor, int line, int column, bool openAtWordStart) |
||||
{ |
||||
var editorUIService = editor == null ? null : editor.GetService(typeof(IEditorUIService)) as IEditorUIService; |
||||
if (editorUIService != null) { |
||||
var document = editor.Document; |
||||
int offset = document.GetOffset(line, column); |
||||
if (openAtWordStart) { |
||||
int wordStart = document.FindPrevWordStart(offset); |
||||
if (wordStart != -1) { |
||||
var wordStartLocation = document.GetLocation(wordStart); |
||||
line = wordStartLocation.Line; |
||||
column = wordStartLocation.Column; |
||||
} |
||||
} |
||||
this.Placement = PlacementMode.Absolute; |
||||
try |
||||
{ |
||||
var caretScreenPos = editorUIService.GetScreenPosition(line, column); |
||||
this.HorizontalOffset = caretScreenPos.X; |
||||
this.VerticalOffset = caretScreenPos.Y; |
||||
} |
||||
catch |
||||
{ |
||||
this.Placement = PlacementMode.MousePoint; |
||||
} |
||||
|
||||
} else { |
||||
// if no editor information, open at mouse positions
|
||||
this.Placement = PlacementMode.MousePoint; |
||||
} |
||||
this.Open(); |
||||
} |
||||
} |
||||
} |
@ -1,12 +0,0 @@
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<UserControl |
||||
x:Class="ICSharpCode.AvalonEdit.AddIn.HiddenDefinition.HiddenDefinitionControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:core="http://icsharpcode.net/sharpdevelop/core" xmlns:local="clr-namespace:ICSharpCode.AvalonEdit.AddIn.Options" |
||||
Background="#FFFFE7"> |
||||
<Border BorderBrush="Black" |
||||
BorderThickness="1" |
||||
Background="Transparent"> |
||||
<StackPanel Background="Transparent"> |
||||
<TextBlock x:Name="DefinitionTextBlock"/> |
||||
</StackPanel> |
||||
</Border> |
||||
</UserControl> |
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
// 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.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Media; |
||||
|
||||
using ICSharpCode.AvalonEdit.AddIn.Options; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn.HiddenDefinition |
||||
{ |
||||
public partial class HiddenDefinitionControl : UserControl |
||||
{ |
||||
public HiddenDefinitionControl() |
||||
{ |
||||
InitializeComponent(); |
||||
DefinitionTextBlock.FontFamily = new FontFamily(CodeEditorOptions.Instance.FontFamily); |
||||
DefinitionTextBlock.FontSize = CodeEditorOptions.Instance.FontSize; |
||||
} |
||||
|
||||
public string DefinitionText { |
||||
get { return this.DefinitionTextBlock.Text; } |
||||
set { this.DefinitionTextBlock.Text = value; } |
||||
} |
||||
} |
||||
} |
@ -1,103 +0,0 @@
@@ -1,103 +0,0 @@
|
||||
// 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.Windows.Controls.Primitives; |
||||
using ICSharpCode.Core.Presentation; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn.HiddenDefinition |
||||
{ |
||||
public class HiddenDefinitionRenderer : IDisposable |
||||
{ |
||||
private CodeEditorView editor; |
||||
private ExtendedPopup popup = new ExtendedPopup(); |
||||
private HiddenDefinitionControl control; |
||||
|
||||
public HiddenDefinitionRenderer(CodeEditorView editorView) |
||||
{ |
||||
this.editor = editorView; |
||||
control = new HiddenDefinitionControl(); |
||||
SD.Workbench.ActiveContentChanged += WorkbenchSingleton_Workbench_ActiveContentChanged; |
||||
} |
||||
|
||||
public BracketSearchResult BracketSearchResult { get; set; } |
||||
|
||||
public void Dispose() |
||||
{ |
||||
SD.Workbench.ActiveContentChanged -= WorkbenchSingleton_Workbench_ActiveContentChanged; |
||||
ClosePopup(); |
||||
popup = null; |
||||
} |
||||
|
||||
public void ClosePopup() |
||||
{ |
||||
if (popup != null && popup.IsOpen) |
||||
popup.IsOpen = false; |
||||
} |
||||
|
||||
public void Show() |
||||
{ |
||||
ClosePopup(); |
||||
|
||||
if (BracketSearchResult == null) return; |
||||
|
||||
// verify if we have a open bracket
|
||||
if (this.editor.Document.GetCharAt(BracketSearchResult.OpeningBracketOffset) != '{') |
||||
return; |
||||
|
||||
var line = GetLineText(BracketSearchResult.OpeningBracketOffset); |
||||
if(line == null) return; |
||||
|
||||
control.DefinitionText = line; |
||||
popup.Child = control; |
||||
popup.HorizontalOffset = 70; |
||||
popup.Placement = PlacementMode.Relative; |
||||
popup.PlacementTarget = editor.TextArea; |
||||
popup.IsOpen = true; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets the line text near the offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset.</param>
|
||||
/// <returns></returns>
|
||||
private string GetLineText(int offset) |
||||
{ |
||||
if (!editor.TextArea.TextView.VisualLinesValid) |
||||
return null; |
||||
|
||||
// get line
|
||||
var documentLine = editor.Document.GetLineByOffset(offset); |
||||
string documentText = editor.Document.Text; |
||||
string lineText = string.Empty; |
||||
int off, length; |
||||
|
||||
do { |
||||
if (documentLine == null || documentLine.IsDeleted) return null; |
||||
off = documentLine.Offset; |
||||
length = documentLine.Length; |
||||
lineText = documentText.Substring(off, length).Trim(); |
||||
|
||||
documentLine = documentLine.PreviousLine; |
||||
} |
||||
while (lineText == "{" || string.IsNullOrEmpty(lineText) || |
||||
lineText.StartsWith("//") || lineText.StartsWith("/*") || |
||||
lineText.StartsWith("*") || lineText.StartsWith("'")); |
||||
|
||||
// check whether the line is visible
|
||||
if (editor.TextArea.TextView.VisualLines[0].StartOffset > off) { |
||||
return this.editor.TextArea.TextView.Document.GetText(off, length); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
private void WorkbenchSingleton_Workbench_ActiveContentChanged(object sender, EventArgs e) |
||||
{ |
||||
ClosePopup(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
// 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.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Controls.Primitives; |
||||
using ICSharpCode.AvalonEdit.Document; |
||||
using ICSharpCode.AvalonEdit.Highlighting; |
||||
using ICSharpCode.AvalonEdit.Rendering; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Editor; |
||||
using ICSharpCode.SharpDevelop.Widgets; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn.HiddenDefinition |
||||
{ |
||||
public class HiddenDefinitionRenderer |
||||
{ |
||||
readonly CodeEditorView editor; |
||||
ExtendedPopup popup; |
||||
int currentStartOffset; |
||||
|
||||
public HiddenDefinitionRenderer(CodeEditorView editorView) |
||||
{ |
||||
this.editor = editorView; |
||||
} |
||||
|
||||
void textView_VisualLinesChanged(object sender, EventArgs e) |
||||
{ |
||||
// This event is registered only while the popup exists
|
||||
var textView = editor.TextArea.TextView; |
||||
VisualLine visualLine = textView.VisualLines.FirstOrDefault(); |
||||
popup.IsOpenIfFocused = visualLine != null && visualLine.StartOffset > currentStartOffset; |
||||
} |
||||
|
||||
public void ClosePopup() |
||||
{ |
||||
if (popup != null) { |
||||
editor.TextArea.TextView.VisualLinesChanged -= textView_VisualLinesChanged; |
||||
popup.IsOpenIfFocused = false; |
||||
popup = null; |
||||
} |
||||
} |
||||
|
||||
public void Show(BracketSearchResult bracketSearchResult) |
||||
{ |
||||
ClosePopup(); |
||||
|
||||
if (bracketSearchResult == null || bracketSearchResult.DefinitionHeaderLength == 0) |
||||
return; |
||||
|
||||
int startOffset = bracketSearchResult.DefinitionHeaderOffset; |
||||
int endOffset = startOffset + bracketSearchResult.DefinitionHeaderLength; |
||||
// show whole line even if the definition is only a part:
|
||||
DocumentLine firstLine = editor.Document.GetLineByOffset(startOffset); |
||||
DocumentLine lastLine = editor.Document.GetLineByOffset(endOffset); |
||||
|
||||
TextEditor popupEditor = new TextEditor(); |
||||
popupEditor.IsReadOnly = true; |
||||
popupEditor.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden; |
||||
popupEditor.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; |
||||
popupEditor.CopySettingsFrom(editor); |
||||
|
||||
IHighlighter oldHighlighter = editor.GetRequiredService<IHighlighter>(); |
||||
FixedHighlighter newHighlighter = FixedHighlighter.CreateView(oldHighlighter, firstLine.Offset, lastLine.EndOffset); |
||||
popupEditor.Document = (TextDocument)newHighlighter.Document; |
||||
popupEditor.TextArea.TextView.LineTransformers.Add(new HighlightingColorizer(newHighlighter)); |
||||
|
||||
popup = new ExtendedPopup(editor.TextArea); |
||||
const double borderThickness = 1; |
||||
popup.Child = new Border() { |
||||
Child = popupEditor, |
||||
BorderBrush = editor.TextArea.Foreground, |
||||
BorderThickness = new Thickness(borderThickness) |
||||
}; |
||||
popup.HorizontalOffset = -borderThickness - editor.TextArea.TextView.ScrollOffset.X; |
||||
popup.Placement = PlacementMode.Top; |
||||
popup.PlacementTarget = editor.TextArea.TextView; |
||||
this.currentStartOffset = firstLine.Offset; |
||||
editor.TextArea.TextView.VisualLinesChanged += textView_VisualLinesChanged; |
||||
if (editor.TextArea.TextView.VisualLinesValid) |
||||
textView_VisualLinesChanged(null, null); // open popup if necessary
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,128 @@
@@ -0,0 +1,128 @@
|
||||
// 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.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.AvalonEdit.Document; |
||||
using ICSharpCode.AvalonEdit.Highlighting; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using ICSharpCode.SharpDevelop; |
||||
|
||||
namespace ICSharpCode.AvalonEdit.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// IHighlighter implementation that returns a fixed set of HighlightedLines.
|
||||
/// </summary>
|
||||
public class FixedHighlighter : IHighlighter |
||||
{ |
||||
/// <summary>
|
||||
/// Creates a new <see cref="FixedHighlighter"/> for a copy of a portion
|
||||
/// of the input document (including the original highlighting).
|
||||
/// </summary>
|
||||
public static FixedHighlighter CreateView(IHighlighter highlighter, int offset, int endOffset) |
||||
{ |
||||
var oldDocument = highlighter.Document; |
||||
// ReadOnlyDocument would be better; but displaying the view in AvalonEdit
|
||||
// requires a TextDocument
|
||||
var newDocument = new TextDocument(oldDocument.CreateSnapshot(offset, endOffset - offset)); |
||||
|
||||
var oldStartLine = oldDocument.GetLineByOffset(offset); |
||||
var oldEndLine = oldDocument.GetLineByOffset(endOffset); |
||||
int oldStartLineNumber = oldStartLine.LineNumber; |
||||
HighlightedLine[] newLines = new HighlightedLine[oldEndLine.LineNumber - oldStartLineNumber + 1]; |
||||
highlighter.BeginHighlighting(); |
||||
try { |
||||
for (int i = 0; i < newLines.Length; i++) { |
||||
HighlightedLine oldHighlightedLine = highlighter.HighlightLine(oldStartLineNumber + i); |
||||
IDocumentLine newLine = newDocument.GetLineByNumber(1 + i); |
||||
HighlightedLine newHighlightedLine = new HighlightedLine(newDocument, newLine); |
||||
MoveSections(oldHighlightedLine.Sections, -offset, newLine.Offset, newLine.EndOffset, newHighlightedLine.Sections); |
||||
newHighlightedLine.ValidateInvariants(); |
||||
newLines[i] = newHighlightedLine; |
||||
} |
||||
} finally { |
||||
highlighter.EndHighlighting(); |
||||
} |
||||
return new FixedHighlighter(newDocument, newLines); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Moves the section start by <paramref name="delta"/> positions;
|
||||
/// and removes the sections outside the (newLineStart,newLineEnd) range.
|
||||
/// </summary>
|
||||
static void MoveSections(IEnumerable<HighlightedSection> sections, int delta, int newLineStart, int newLineEnd, IList<HighlightedSection> result) |
||||
{ |
||||
foreach (var section in sections) { |
||||
int newOffset = section.Offset + delta; |
||||
int newEndOffset = section.Offset + section.Length + delta; |
||||
newOffset = newOffset.CoerceValue(newLineStart, newLineEnd); |
||||
newEndOffset = newEndOffset.CoerceValue(newLineStart, newLineEnd); |
||||
|
||||
if (newOffset < newLineEnd && newEndOffset > newLineStart) { |
||||
result.Add( |
||||
new HighlightedSection { |
||||
Offset = newOffset, |
||||
Length = newEndOffset - newOffset, |
||||
Color = section.Color |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
readonly IDocument document; |
||||
readonly HighlightedLine[] lines; |
||||
|
||||
public FixedHighlighter(IDocument document, HighlightedLine[] lines) |
||||
{ |
||||
if (lines.Length != document.LineCount) |
||||
throw new ArgumentException("Wrong number of highlighted lines"); |
||||
this.document = document; |
||||
this.lines = lines; |
||||
} |
||||
|
||||
event HighlightingStateChangedEventHandler IHighlighter.HighlightingStateChanged { |
||||
add { } |
||||
remove { } |
||||
} |
||||
|
||||
public IDocument Document { |
||||
get { return document; } |
||||
} |
||||
|
||||
HighlightingColor IHighlighter.DefaultTextColor { |
||||
get { return null; } |
||||
} |
||||
|
||||
IEnumerable<HighlightingColor> IHighlighter.GetColorStack(int lineNumber) |
||||
{ |
||||
return Enumerable.Empty<HighlightingColor>(); |
||||
} |
||||
|
||||
public HighlightedLine HighlightLine(int lineNumber) |
||||
{ |
||||
return lines[lineNumber - 1]; |
||||
} |
||||
|
||||
void IHighlighter.UpdateHighlightingState(int lineNumber) |
||||
{ |
||||
} |
||||
|
||||
void IHighlighter.BeginHighlighting() |
||||
{ |
||||
} |
||||
|
||||
void IHighlighter.EndHighlighting() |
||||
{ |
||||
} |
||||
|
||||
HighlightingColor IHighlighter.GetNamedColor(string name) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
void IDisposable.Dispose() |
||||
{ |
||||
} |
||||
} |
||||
} |
@ -1,67 +0,0 @@
@@ -1,67 +0,0 @@
|
||||
// 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.Runtime.InteropServices; |
||||
using System.Windows; |
||||
using System.Windows.Controls.Primitives; |
||||
using System.Windows.Interop; |
||||
|
||||
namespace ICSharpCode.Core.Presentation |
||||
{ |
||||
/// <summary>
|
||||
/// Extends WPF popup to prevent it from being the topmost window on the screen.
|
||||
/// </summary>
|
||||
public class ExtendedPopup : Popup |
||||
{ |
||||
IntPtr hwnd; |
||||
|
||||
protected override void OnOpened(EventArgs e) |
||||
{ |
||||
hwnd = ((HwndSource)PresentationSource.FromVisual(Child)).Handle; |
||||
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, NoChangeFlags); |
||||
|
||||
Application.Current.Activated += ApplicationActivated; |
||||
Application.Current.Deactivated += ApplicationDeactivated; |
||||
} |
||||
|
||||
protected override void OnClosed(EventArgs e) |
||||
{ |
||||
Application.Current.Activated -= ApplicationActivated; |
||||
Application.Current.Deactivated -= ApplicationDeactivated; |
||||
} |
||||
|
||||
void ApplicationActivated(object sender, EventArgs e) |
||||
{ |
||||
LoggingService.Debug("Application activated!"); |
||||
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, NoChangeFlags | SWP_SHOWWINDOW); |
||||
} |
||||
|
||||
void ApplicationDeactivated(object sender, EventArgs e) |
||||
{ |
||||
LoggingService.Debug("Application deactivated!"); |
||||
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, NoChangeFlags | SWP_HIDEWINDOW); |
||||
} |
||||
|
||||
#region Win32 API
|
||||
// for all possible flags see http://msdn.microsoft.com/en-us/library/ms633545%28VS.85%29.aspx
|
||||
|
||||
const int SWP_NOSIZE = 0x0001; |
||||
const int SWP_NOMOVE = 0x0002; |
||||
const int SWP_NOACTIVATE = 0x0010; |
||||
const int SWP_SHOWWINDOW = 0x0040; |
||||
const int SWP_HIDEWINDOW = 0x0080; |
||||
|
||||
// SWP_NOACTIVATE fixes SD-1728 - http://bugtracker.sharpdevelop.net/Default.aspx?p=4&i=1728
|
||||
static readonly uint NoChangeFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE; |
||||
|
||||
static readonly IntPtr HWND_TOP = new IntPtr(0); |
||||
static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); |
||||
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); |
||||
|
||||
[DllImport("user32.dll", SetLastError=true, EntryPoint="SetWindowPos")] |
||||
[return: MarshalAs(UnmanagedType.Bool)] |
||||
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); |
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
// 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.Windows; |
||||
using System.Windows.Controls.Primitives; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Widgets |
||||
{ |
||||
/// <summary>
|
||||
/// A popup that is only visible while the parent control or the popup itself has the keyboard focus.
|
||||
/// </summary>
|
||||
public class ExtendedPopup : Popup |
||||
{ |
||||
readonly UIElement parent; |
||||
|
||||
public ExtendedPopup(UIElement parent) |
||||
{ |
||||
if (parent == null) |
||||
throw new ArgumentNullException("parent"); |
||||
this.parent = parent; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets whether the popup is currently visible.
|
||||
/// </summary>
|
||||
public new bool IsOpen { |
||||
get { return base.IsOpen; } |
||||
// Prevent consumers from accessing the setter directly
|
||||
} |
||||
|
||||
bool openIfFocused; |
||||
|
||||
public bool IsOpenIfFocused { |
||||
get { return openIfFocused; } |
||||
set { |
||||
if (openIfFocused != value) { |
||||
openIfFocused = value; |
||||
if (value) { |
||||
parent.IsKeyboardFocusedChanged += parent_IsKeyboardFocusedChanged; |
||||
} else { |
||||
parent.IsKeyboardFocusedChanged -= parent_IsKeyboardFocusedChanged; |
||||
} |
||||
OpenOrClose(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void parent_IsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e) |
||||
{ |
||||
OpenOrClose(); |
||||
} |
||||
|
||||
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) |
||||
{ |
||||
base.OnIsKeyboardFocusWithinChanged(e); |
||||
OpenOrClose(); |
||||
} |
||||
|
||||
void OpenOrClose() |
||||
{ |
||||
bool newIsOpen = openIfFocused && (parent.IsKeyboardFocused || this.IsKeyboardFocusWithin); |
||||
base.IsOpen = newIsOpen; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue