Skip to content

Commit

Permalink
! Reworked underlying NaviBar
Browse files Browse the repository at this point in the history
wmjordan committed Dec 7, 2019
1 parent 84ec16b commit 9107dc5
Showing 9 changed files with 236 additions and 126 deletions.
4 changes: 3 additions & 1 deletion Codist/Codist.csproj
Original file line number Diff line number Diff line change
@@ -68,6 +68,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Commands\VersionInfoBar.cs" />
<Compile Include="Controls\IContextMenuHost.cs" />
<Compile Include="NaviBar\NaviBar.cs" />
<Compile Include="QuickInfo\CSharpOpCodeQuickInfo.cs" />
<Compile Include="Taggers\Classifications.cs" />
<Compile Include="Taggers\CommentFormats.cs" />
@@ -680,7 +682,7 @@
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
<ProjectExtensions>
<VisualStudio>
<UserProperties BuildVersion_BuildVersioningStyle="None.None.None.Increment" BuildVersion_UpdateFileVersion="True" BuildVersion_StartDate="2000/1/1" />
<UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UpdateFileVersion="True" BuildVersion_BuildVersioningStyle="None.None.None.Increment" />
</VisualStudio>
</ProjectExtensions>
<Import Project="..\packages\Microsoft.VisualStudio.Threading.Analyzers.16.0.102\build\Microsoft.VisualStudio.Threading.Analyzers.targets" Condition="Exists('..\packages\Microsoft.VisualStudio.Threading.Analyzers.16.0.102\build\Microsoft.VisualStudio.Threading.Analyzers.targets')" />
14 changes: 14 additions & 0 deletions Codist/Controls/IContextMenuHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Codist.Controls
{
interface IContextMenuHost
{
void ShowContextMenu(RoutedEventArgs args);
}
}
2 changes: 1 addition & 1 deletion Codist/Controls/NavigationBar.xaml
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Menu}">
<ControlTemplate TargetType="{x:Type ToolBar}">
<StackPanel CanHorizontallyScroll="True" MaxHeight="22" ClipToBounds="True" Orientation="Horizontal" Background="{DynamicResource VsBrush.CommandBarMenuBackgroundGradient}" IsItemsHost="True" />
</ControlTemplate>
</Setter.Value>
41 changes: 40 additions & 1 deletion Codist/Controls/ThemedButton.cs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@

namespace Codist.Controls
{
public sealed class ThemedButton : Button
public sealed class ThemedButton : Button, IContextMenuHost
{
readonly Action _clickHanler;

@@ -31,9 +31,48 @@ public ThemedButton(object content, object toolTip, RoutedEventHandler clickHand
Click += clickHandler;
}

public void ShowContextMenu(RoutedEventArgs args) {
}

void ThemedButton_Click(object sender, RoutedEventArgs e) {
_clickHanler?.Invoke();
}

internal void PerformClick() {
OnClick();
}
}

public class ThemedImageButton : Button
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(ThemedImageButton));
public static readonly DependencyProperty IsHighlightedProperty = DependencyProperty.Register("IsHighlighted", typeof(bool), typeof(ThemedImageButton));
bool _IsChecked, _IsHighlighted;

public ThemedImageButton(int imageId, TextBlock content) {
Content = new StackPanel {
Orientation = Orientation.Horizontal,
Children = {
ThemeHelper.GetImage(imageId).WrapMargin(WpfHelper.SmallHorizontalMargin),
content
}
};
Header = content;
this.ReferenceStyle(typeof(ThemedImageButton));
this.ReferenceCrispImageBackground(EnvironmentColors.MainWindowActiveCaptionColorKey);
}
public object Header { get; }
public bool IsChecked {
get => _IsChecked;
set => SetValue(IsCheckedProperty, _IsChecked = value);
}
public bool IsHighlighted {
get => _IsHighlighted;
set => SetValue(IsHighlightedProperty, _IsHighlighted = value);
}
internal void PerformClick() {
OnClick();
}
}

public sealed class ThemedToggleButton : System.Windows.Controls.Primitives.ToggleButton
28 changes: 28 additions & 0 deletions Codist/Controls/ThemedControls.xaml
Original file line number Diff line number Diff line change
@@ -63,4 +63,32 @@
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type c:ThemedImageButton}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="1,2,3,2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:ThemedImageButton}">
<Border Name="Border" BorderThickness="{TemplateBinding BorderThickness}" Margin="{TemplateBinding Margin}" Padding="{TemplateBinding Padding}" VerticalAlignment="Center">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource {x:Static vsp:EnvironmentColors.CommandBarMenuItemMouseOverBrushKey}}"/>
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource VsBrush.CommandBarHoverOverSelectedIconBorder}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource VsBrush.FileTabSelectedGradientTop}"/>
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource VsBrush.FileTabSelectedGradientTop}"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource {x:Static vsp:EnvironmentColors.CommandBarSelectedBrushKey}}"/>
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource {x:Static vsp:EnvironmentColors.CommandBarSelectedBorderBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
6 changes: 3 additions & 3 deletions Codist/Helpers/WpfHelper.cs
Original file line number Diff line number Diff line change
@@ -366,7 +366,7 @@ public static ResourceDictionary MergeWith(this ResourceDictionary dictionary, R

#region Others
public static TItem GetFirst<TItem>(this ItemCollection items, Predicate<TItem> predicate)
where TItem : FrameworkElement {
where TItem : UIElement {
foreach (var item in items) {
var i = item as TItem;
if (i != null && (predicate == null || predicate(i))) {
@@ -376,7 +376,7 @@ public static TItem GetFirst<TItem>(this ItemCollection items, Predicate<TItem>
return null;
}
public static bool FocusFirst<TItem>(this ItemCollection items)
where TItem : FrameworkElement {
where TItem : UIElement {
foreach (var item in items) {
if ((item as TItem)?.Focus() == true) {
return true;
@@ -385,7 +385,7 @@ public static bool FocusFirst<TItem>(this ItemCollection items)
return false;
}
public static bool FocusLast<TItem>(this ItemCollection items)
where TItem : FrameworkElement {
where TItem : UIElement {
for (int i = items.Count - 1; i >= 0; i--) {
if ((items[i] as TItem)?.Focus() == true) {
return true;
155 changes: 76 additions & 79 deletions Codist/NaviBar/CSharpBar.cs
Original file line number Diff line number Diff line change
@@ -21,35 +21,26 @@

namespace Codist.NaviBar
{
public sealed class CSharpBar : Menu, INaviBar
public sealed class CSharpBar : NaviBar
{
internal const string SyntaxNodeRange = nameof(SyntaxNodeRange);
readonly IWpfTextView _View;
readonly IAdornmentLayer _SyntaxNodeRangeAdornment;
readonly SemanticContext _SemanticContext;
readonly ExternalAdornment _SymbolListContainer;

CancellationTokenSource _cancellationSource = new CancellationTokenSource();
readonly RootItem _RootItem;
NodeItem _MouseHoverItem;
SymbolList _SymbolList;
ThemedMenuItem _ActiveItem;
ThemedImageButton _ActiveItem;

public CSharpBar(IWpfTextView textView) {
_View = textView;
_SyntaxNodeRangeAdornment = _View.GetAdornmentLayer(SyntaxNodeRange);
_SymbolListContainer = _View.Properties.GetOrCreateSingletonProperty(() => new ExternalAdornment(textView));
public CSharpBar(IWpfTextView textView) : base(textView) {
_SyntaxNodeRangeAdornment = View.GetAdornmentLayer(SyntaxNodeRange);
_SemanticContext = SemanticContext.GetOrCreateSingetonInstance(textView);
this.SetBackgroundForCrispImage(ThemeHelper.TitleBackgroundColor);
textView.Properties.AddProperty(nameof(NaviBar), this);
Name = nameof(CSharpBar);
Resources = SharedDictionaryManager.Menu;
SetResourceReference(BackgroundProperty, VsBrushes.CommandBarMenuBackgroundGradientKey);
SetResourceReference(ForegroundProperty, VsBrushes.CommandBarTextInactiveKey);
Items.Add(_RootItem = new RootItem(this));
_View.TextBuffer.Changed += TextBuffer_Changed;
_View.Selection.SelectionChanged += Update;
_View.Closed += ViewClosed;
View.TextBuffer.Changed += TextBuffer_Changed;
View.Selection.SelectionChanged += Update;
View.Closed += ViewClosed;
Config.Updated += Config_Updated;
Update(this, EventArgs.Empty);
if (_SemanticContext.Compilation != null) {
@@ -83,7 +74,7 @@ protected override void OnMouseMove(MouseEventArgs e) {
if (_SyntaxNodeRangeAdornment.IsEmpty == false) {
_SyntaxNodeRangeAdornment.RemoveAllAdornments();
}
var span = item.Node.Span.CreateSnapshotSpan(_View.TextSnapshot);
var span = item.Node.Span.CreateSnapshotSpan(View.TextSnapshot);
if (span.Length > 0) {
try {
HighlightNodeRanges(item.Node, span);
@@ -102,8 +93,8 @@ protected override void OnMouseMove(MouseEventArgs e) {
}

void HighlightNodeRanges(SyntaxNode node, SnapshotSpan span) {
_SyntaxNodeRangeAdornment.AddAdornment(span, null, new GeometryAdornment(ThemeHelper.MenuHoverBackgroundColor, _View.TextViewLines.GetMarkerGeometry(span), 3));
var p = _View.Caret.Position.BufferPosition;
_SyntaxNodeRangeAdornment.AddAdornment(span, null, new GeometryAdornment(ThemeHelper.MenuHoverBackgroundColor, View.TextViewLines.GetMarkerGeometry(span), 3));
var p = View.Caret.Position.BufferPosition;
if (span.Contains(p) == false) {
return;
}
@@ -113,8 +104,8 @@ void HighlightNodeRanges(SyntaxNode node, SnapshotSpan span) {
&& n.Span.Length != span.Length) {
var nodeKind = n.Kind();
if (nodeKind != SyntaxKind.Block) {
span = n.Span.CreateSnapshotSpan(_View.TextSnapshot);
_SyntaxNodeRangeAdornment.AddAdornment(span, null, new GeometryAdornment(ThemeHelper.MenuHoverBackgroundColor, _View.TextViewLines.GetMarkerGeometry(span), nodeKind.IsSyntaxBlock() || nodeKind.IsDeclaration() ? 1 : 0));
span = n.Span.CreateSnapshotSpan(View.TextSnapshot);
_SyntaxNodeRangeAdornment.AddAdornment(span, null, new GeometryAdornment(ThemeHelper.MenuHoverBackgroundColor, View.TextViewLines.GetMarkerGeometry(span), nodeKind.IsSyntaxBlock() || nodeKind.IsDeclaration() ? 1 : 0));
}
}
n = n.Parent;
@@ -212,19 +203,19 @@ async Task Update(CancellationToken token) {
}

async Task<List<SyntaxNode>> UpdateModelAndGetContainingNodesAsync(CancellationToken token) {
var start = _View.GetCaretPosition();
var start = View.GetCaretPosition();
if (await _SemanticContext.UpdateAsync(start, token) == false) {
return new List<SyntaxNode>();
}
return _SemanticContext.GetContainingNodes(start, Config.Instance.NaviBarOptions.MatchFlags(NaviBarOptions.SyntaxDetail), Config.Instance.NaviBarOptions.MatchFlags(NaviBarOptions.RegionOnBar));
}

void ViewClosed(object sender, EventArgs e) {
_View.Selection.SelectionChanged -= Update;
_View.TextBuffer.Changed -= TextBuffer_Changed;
View.Selection.SelectionChanged -= Update;
View.TextBuffer.Changed -= TextBuffer_Changed;
Config.Updated -= Config_Updated;
SyncHelper.CancelAndDispose(ref _cancellationSource, false);
_View.Closed -= ViewClosed;
View.Closed -= ViewClosed;
}

void Config_Updated(object sender, ConfigUpdatedEventArgs e) {
@@ -240,10 +231,10 @@ void Config_Updated(object sender, ConfigUpdatedEventArgs e) {
}

#region Menu handler
public void ShowRootItemMenu() {
public override void ShowRootItemMenu() {
_RootItem.ShowNamespaceAndTypeMenu();
}
public void ShowActiveItemMenu() {
public override void ShowActiveItemMenu() {
for (int i = Items.Count - 1; i >= 0; i--) {
var item = Items[i] as NodeItem;
if (item != null && item.Node.Kind().IsTypeDeclaration()) {
@@ -261,16 +252,18 @@ void SetupSymbolListMenu(SymbolList list) {
list.MouseLeftButtonUp += MenuItemSelect;
}

void ShowMenu(ThemedMenuItem barItem, SymbolList menu) {
void ShowMenu(ThemedImageButton barItem, SymbolList menu) {
if (_SymbolList != menu) {
_SymbolListContainer.Children.Remove(_SymbolList);
_SymbolListContainer.Children.Add(menu);
ListContainer.Children.Remove(_SymbolList);
ListContainer.Children.Add(menu);
_SymbolList = menu;
_ActiveItem?.Highlight(false);
if (_ActiveItem != null) {
_ActiveItem.IsHighlighted = false;
}
}
_ActiveItem = barItem;
_ActiveItem.Highlight(true);
menu.ItemsControlMaxHeight = _SymbolListContainer.ActualHeight / 2;
barItem.IsHighlighted = true;
menu.ItemsControlMaxHeight = ListContainer.ActualHeight / 2;
menu.RefreshItemsSource();
menu.ScrollToSelectedItem();
menu.PreviewKeyUp -= OnMenuKeyUp;
@@ -280,7 +273,7 @@ void ShowMenu(ThemedMenuItem barItem, SymbolList menu) {

void PositionMenu() {
if (_SymbolList != null) {
Canvas.SetLeft(_SymbolList, _ActiveItem.TransformToVisual(_ActiveItem.GetParent<Grid>()).Transform(new Point()).X - _View.VisualElement.TranslatePoint(new Point(), _View.VisualElement.GetParent<Grid>()).X);
Canvas.SetLeft(_SymbolList, _ActiveItem.TransformToVisual(_ActiveItem.GetParent<Grid>()).Transform(new Point()).X - View.VisualElement.TranslatePoint(new Point(), View.VisualElement.GetParent<Grid>()).X);
Canvas.SetTop(_SymbolList, -1);
}
}
@@ -294,12 +287,12 @@ void OnMenuKeyUp(object sender, KeyEventArgs e) {
int i;
if (Keyboard.Modifiers.MatchFlags(ModifierKeys.Shift)) {
if ((i = Items.IndexOf(_ActiveItem)) > 0) {
((ThemedMenuItem)Items[i - 1]).PerformClick();
((ThemedImageButton)Items[i - 1]).PerformClick();
}
}
else {
if ((i = Items.IndexOf(_ActiveItem)) < Items.Count - 1) {
((ThemedMenuItem)Items[i + 1]).PerformClick();
((ThemedImageButton)Items[i + 1]).PerformClick();
}
}
e.Handled = true;
@@ -308,10 +301,12 @@ void OnMenuKeyUp(object sender, KeyEventArgs e) {

void HideMenu() {
if (_SymbolList != null) {
_SymbolListContainer.Children.Remove(_SymbolList);
ListContainer.Children.Remove(_SymbolList);
_SymbolList.SelectedItem = null;
_SymbolList = null;
_ActiveItem?.Highlight(false);
if (_ActiveItem != null) {
_ActiveItem.IsHighlighted = false;
}
_ActiveItem = null;
}
}
@@ -321,7 +316,7 @@ void MenuItemSelect(object sender, MouseButtonEventArgs e) {
if (menu.SelectedIndex == -1 || e.OccursOn<ListBoxItem>() == false) {
return;
}
_View.VisualElement.Focus();
View.VisualElement.Focus();
(menu.SelectedItem as SymbolItem)?.GoToSource();
}
#endregion
@@ -392,22 +387,20 @@ static string TrimNonLetterOrDigitCharacters(string title) {
return s > 0 || e < title.Length ? title.Substring(s, e - s) : title;
}

sealed class RootItem : ThemedMenuItem
sealed class RootItem : ThemedImageButton, IContextMenuHost
{
readonly CSharpBar _Bar;
readonly SymbolList _Menu;
readonly MemberFinderBox _FinderBox;
readonly SearchScopeBox _ScopeBox;
readonly TextBlock _Note;

public RootItem(CSharpBar bar) {
public RootItem(CSharpBar bar) : base(KnownImageIds.Namespace, new ThemedToolBarText()) {
_Bar = bar;
Icon = ThemeHelper.GetImage(KnownImageIds.Namespace);
this.ReferenceCrispImageBackground(EnvironmentColors.MainWindowActiveCaptionColorKey);
SetResourceReference(ForegroundProperty, VsBrushes.CommandBarTextActiveKey);
Header = new ThemedToolBarText();
_Menu = new SymbolList(bar._SemanticContext) {
Container = _Bar._SymbolListContainer,
Container = _Bar.ListContainer,
ContainerType = SymbolListType.NodeList,
Header = new StackPanel {
Margin = WpfHelper.MenuItemMargin,
@@ -464,7 +457,7 @@ internal void ShowNamespaceAndTypeMenu() {
_Note.Clear();
if (Config.Instance.NaviBarOptions.MatchFlags(NaviBarOptions.LineOfCode)) {
_Note.Append(ThemeHelper.GetImage(KnownImageIds.Code))
.Append(_Bar._View.TextSnapshot.LineCount);
.Append(_Bar.View.TextSnapshot.LineCount);
}
_Bar.ShowMenu(this, _Menu);
}
@@ -481,7 +474,7 @@ void PopulateTypes() {
}

void MarkEnclosingType() {
int pos = _Bar._View.GetCaretPosition();
int pos = _Bar.View.GetCaretPosition();
for (int i = _Menu.Symbols.Count - 1; i >= 0; i--) {
if (_Menu.Symbols[i].SelectIfContainsPosition(pos)) {
return;
@@ -574,6 +567,11 @@ async Task FindDeclarationsAsync(string symbolName, CancellationToken token) {
_Menu.Add(item, true);
}
}

void IContextMenuHost.ShowContextMenu(RoutedEventArgs args) {
ShowNamespaceAndTypeMenu();
}

sealed class MemberFinderBox : ThemedTextBox
{
public MemberFinderBox() : base() {
@@ -587,7 +585,8 @@ public MemberFinderBox() : base() {
}
}
}
sealed class NodeItem : ThemedMenuItem, ISymbolFilter

sealed class NodeItem : ThemedImageButton, ISymbolFilter, IContextMenuHost
{
readonly int _ImageId;
readonly CSharpBar _Bar;
@@ -597,12 +596,11 @@ sealed class NodeItem : ThemedMenuItem, ISymbolFilter
ISymbol _Symbol;
List<ISymbol> _ReferencedDocs;

public NodeItem(CSharpBar bar, SyntaxNode node) {
public NodeItem(CSharpBar bar, SyntaxNode node)
: base (node.GetImageId(), new ThemedMenuText(node.GetDeclarationSignature() ?? String.Empty)) {
_Bar = bar;
_ImageId = node.GetImageId();
Header = new ThemedMenuText(node.GetDeclarationSignature() ?? String.Empty);
Node = node;
Icon = ThemeHelper.GetImage(_ImageId);
this.ReferenceCrispImageBackground(EnvironmentColors.MainWindowActiveCaptionColorKey);
SetResourceReference(ForegroundProperty, VsBrushes.CommandBarTextActiveKey);
Click += HandleClick;
@@ -614,6 +612,27 @@ public NodeItem(CSharpBar bar, SyntaxNode node) {
public bool HasReferencedDocs => _ReferencedDocs != null && _ReferencedDocs.Count > 0;
public List<ISymbol> ReferencedDocs => _ReferencedDocs ?? (_ReferencedDocs = new List<ISymbol>());

public void ShowContextMenu(RoutedEventArgs args) {
if (ContextMenu == null) {
var m = new CSharpSymbolContextMenu(_Bar._SemanticContext) {
SyntaxNode = Node
};
m.AddNodeCommands();
var s = Symbol;
if (s != null) {
m.Symbol = s;
m.Items.Add(new Separator());
m.AddAnalysisCommands();
m.AddSymbolCommands();
m.AddTitleItem(Node.GetDeclarationSignature());
}
//m.PlacementTarget = this;
//m.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
ContextMenu = m;
}
ContextMenu.IsOpen = true;
}

async void HandleClick(object sender, RoutedEventArgs e) {
SyncHelper.CancelAndDispose(ref _Bar._cancellationSource, true);
if (_Menu != null && _Bar._SymbolList == _Menu) {
@@ -624,7 +643,7 @@ async void HandleClick(object sender, RoutedEventArgs e) {
var span = Node.FullSpan;
if (span.Contains(_Bar._SemanticContext.Position) && Node.SyntaxTree.FilePath == _Bar._SemanticContext.Document.FilePath
|| Node.IsKind(SyntaxKind.RegionDirectiveTrivia)) {
_Bar._View.SelectNode(Node, Keyboard.Modifiers != ModifierKeys.Control);
_Bar.View.SelectNode(Node, Keyboard.Modifiers != ModifierKeys.Control);
}
else {
Node.GetIdentifierToken().GetLocation().GoToSource();
@@ -656,7 +675,7 @@ async Task CreateMenuForTypeSymbolNodeAsync(CancellationToken cancellationToken)
return;
}
_Menu = new SymbolList(_Bar._SemanticContext) {
Container = _Bar._SymbolListContainer,
Container = _Bar.ListContainer,
ContainerType = SymbolListType.NodeList
};
_Menu.Header = new WrapPanel {
@@ -700,7 +719,7 @@ async Task RefreshItemsAsync(SyntaxNode node, CancellationToken cancellationToke
return;
}
// select node item which contains caret
var pos = _Bar._View.GetCaretPosition();
var pos = _Bar.View.GetCaretPosition();
foreach (var item in _Menu.Symbols) {
if (item.Type != SymbolItemType.Container) {
if (item.IsExternal || cancellationToken.IsCancellationRequested
@@ -739,7 +758,7 @@ void AddMemberDeclarations(SyntaxNode node, bool isExternal) {
: null;
byte regionJustStart = UNDEFINED; // undefined, prevent #endregion show up on top of menu items
bool selected = false;
int pos = _Bar._View.GetCaretPosition();
int pos = _Bar.View.GetCaretPosition();
SyntaxNode lastNode = null;
foreach (var child in node.ChildNodes()) {
var childKind = child.Kind();
@@ -879,27 +898,6 @@ void ShowPropertyValue(SymbolItem propertyItem) {
}
}

protected override void OnContextMenuOpening(ContextMenuEventArgs e) {
if (ContextMenu == null) {
var m = new CSharpSymbolContextMenu(_Bar._SemanticContext) {
SyntaxNode = Node
};
m.AddNodeCommands();
var s = Symbol;
if (s != null) {
m.Symbol = s;
m.Items.Add(new Separator());
m.AddAnalysisCommands();
m.AddSymbolCommands();
m.AddTitleItem(Node.GetDeclarationSignature());
}
m.PlacementTarget = this;
m.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
ContextMenu = m;
}
base.OnContextMenuOpening(e);
}

protected override void OnToolTipOpening(ToolTipEventArgs e) {
base.OnToolTipOpening(e);
if (Config.Instance.NaviBarOptions.MatchFlags(NaviBarOptions.SymbolToolTip) == false) {
@@ -929,16 +927,15 @@ bool ISymbolFilter.Filter(int filterTypes) {
}
}

sealed class DocItem : ThemedMenuItem
sealed class DocItem : ThemedImageButton
{
readonly CSharpBar _Bar;
readonly ISymbol _SyntaxTree;

public DocItem(CSharpBar bar, ISymbol syntaxTree) {
public DocItem(CSharpBar bar, ISymbol syntaxTree)
: base (KnownImageIds.GoToDefinition, new ThemedMenuText(syntaxTree.GetOriginalName())) {
_Bar = bar;
_SyntaxTree = syntaxTree;
Header = new ThemedMenuText(syntaxTree.GetOriginalName());
Icon = ThemeHelper.GetImage(KnownImageIds.GoToDefinition);
Opacity = 0.8;
}

73 changes: 32 additions & 41 deletions Codist/NaviBar/MarkdownBar.cs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@

namespace Codist.NaviBar
{
public sealed class MarkdownBar : ToolBar, INaviBar
public sealed class MarkdownBar : NaviBar
{
const string DefaultActiveTitle = "Headings";
static readonly IClassificationType
@@ -24,34 +24,24 @@ static readonly IClassificationType
_H4 = ServicesHelper.Instance.ClassificationTypeRegistry.GetClassificationType(Constants.MarkdownHeading4),
_H5 = ServicesHelper.Instance.ClassificationTypeRegistry.GetClassificationType(Constants.MarkdownHeading5),
_H6 = ServicesHelper.Instance.ClassificationTypeRegistry.GetClassificationType(Constants.MarkdownHeading6);
readonly IWpfTextView _View;
readonly ITextSearchService2 _TextSearch;
readonly ExternalAdornment _ListContainer;
readonly TaggerResult _Tags;
readonly ThemedToolBarText _ActiveTitleLabel;
MarkdownList _TitleList;
LocationItem[] _Titles;
UIElement _ActiveItem;
ThemedImageButton _ActiveItem;

public MarkdownBar(IWpfTextView view, ITextSearchService2 textSearch) {
_View = view;
public MarkdownBar(IWpfTextView view, ITextSearchService2 textSearch) : base(view) {
_TextSearch = textSearch;
_ListContainer = _View.Properties.GetOrCreateSingletonProperty(() => new ExternalAdornment(view));
_Tags = _View.Properties.GetProperty<TaggerResult>(typeof(TaggerResult));
_Tags = view.Properties.GetProperty<TaggerResult>(typeof(TaggerResult));
Name = nameof(MarkdownBar);
this.SetBackgroundForCrispImage(ThemeHelper.TitleBackgroundColor);
view.Properties.AddProperty(nameof(NaviBar), this);
view.Selection.SelectionChanged += Update;
view.TextBuffer.PostChanged += Update;
view.Closed += View_Closed;
Resources = SharedDictionaryManager.Menu;
SetResourceReference(BackgroundProperty, VsBrushes.CommandBarMenuBackgroundGradientKey);
SetResourceReference(ForegroundProperty, VsBrushes.CommandBarTextInactiveKey);
_ActiveTitleLabel = new ThemedToolBarText(DefaultActiveTitle);
Items.Add(_ActiveItem = new ThemedButton(new StackPanel {
Orientation = Orientation.Horizontal,
Children = { ThemeHelper.GetImage(KnownImageIds.PageHeader), _ActiveTitleLabel }
}, null, ShowTitleList) { Padding = WpfHelper.SmallMargin });
_ActiveItem = new ThemedImageButton(KnownImageIds.PageHeader, _ActiveTitleLabel);
_ActiveItem.Click += ShowTitleList;
Items.Add(_ActiveItem);
//AddItem(KnownImageIds.Bold, ToggleBold);
//AddItem(KnownImageIds.Italic, ToggleItalic);
//AddItem(KnownImageIds.MarkupTag, ToggleCode);
@@ -60,20 +50,21 @@ public MarkdownBar(IWpfTextView view, ITextSearchService2 textSearch) {
}

void View_Closed(object sender, EventArgs e) {
_View.Closed -= View_Closed;
_View.Selection.SelectionChanged -= Update;
View.Closed -= View_Closed;
View.Selection.SelectionChanged -= Update;
}

void Update(object sender, EventArgs e) {
HideMenu();
_ActiveTitleLabel.Text = _Tags.GetPreceedingTaggedSpan(_View.GetCaretPosition().Position)?.ContentText ?? DefaultActiveTitle;
_ActiveTitleLabel.Text = _Tags.GetPreceedingTaggedSpan(View.GetCaretPosition().Position)?.ContentText ?? DefaultActiveTitle;
}

void HideMenu() {
if (_TitleList != null) {
_ListContainer.Children.Remove(_TitleList);
ListContainer.Children.Remove(_TitleList);
_TitleList.SelectedItem = null;
_TitleList = null;
_ActiveItem.IsHighlighted = false;
}
}

@@ -93,8 +84,8 @@ void ToggleHyperLink(object sender, RoutedEventArgs e) {
var s = WrapWith("[", "](url)", false);
if (s.Snapshot != null) {
// select the "url"
_View.Selection.Select(new SnapshotSpan(s.Snapshot, s.Start + s.Length - 4, 3), false);
_View.Caret.MoveTo(s.End - 1);
View.Selection.Select(new SnapshotSpan(s.Snapshot, s.Start + s.Length - 4, 3), false);
View.Caret.MoveTo(s.End - 1);
}
}

@@ -107,16 +98,16 @@ void ShowTitleList(object sender, RoutedEventArgs e) {
HideMenu();
return;
}
_ActiveItem = sender as UIElement;
ShowRootItemMenu();
}

public void ShowRootItemMenu() {
public override void ShowRootItemMenu() {
_ActiveItem.IsHighlighted = true;
var titles = _Titles = Array.ConvertAll(_Tags.GetTags(), t => new LocationItem(t));
var menu = new MarkdownList(this) {
ItemsControlMaxHeight = _View.ViewportHeight / 2,
ItemsControlMaxHeight = View.ViewportHeight / 2,
ItemsSource = titles,
SelectedIndex = GetSelectedTagIndex(titles, _View.GetCaretPosition().Position),
SelectedIndex = GetSelectedTagIndex(titles, View.GetCaretPosition().Position),
FilteredItems = new System.Windows.Data.ListCollectionView(titles)
};
menu.ScrollToSelectedItem();
@@ -125,16 +116,16 @@ public void ShowRootItemMenu() {
ScrollViewer.SetCanContentScroll(menu, true);
}
if (_TitleList != menu) {
_ListContainer.Children.Remove(_TitleList);
_ListContainer.Children.Add(menu);
ListContainer.Children.Remove(_TitleList);
ListContainer.Children.Add(menu);
_TitleList = menu;
}
if (menu != null) {
Canvas.SetLeft(menu, _ActiveItem.TransformToVisual(_ActiveItem.GetParent<Grid>()).Transform(new Point()).X - _View.VisualElement.TranslatePoint(new Point(), _View.VisualElement.GetParent<Grid>()).X);
Canvas.SetLeft(menu, _ActiveItem.TransformToVisual(_ActiveItem.GetParent<Grid>()).Transform(new Point()).X - View.VisualElement.TranslatePoint(new Point(), View.VisualElement.GetParent<Grid>()).X);
Canvas.SetTop(menu, -1);
}
}
public void ShowActiveItemMenu() {
public override void ShowActiveItemMenu() {
ShowRootItemMenu();
}

@@ -154,19 +145,19 @@ static int GetSelectedTagIndex(LocationItem[] titles, int p) {

void MenuItemSelect(object sender, MouseButtonEventArgs e) {
if (e.OccursOn<ListBoxItem>()) {
_View.VisualElement.Focus();
(((ListBox)sender).SelectedItem as LocationItem)?.GoToSource(_View);
View.VisualElement.Focus();
(((ListBox)sender).SelectedItem as LocationItem)?.GoToSource(View);
}
}

SnapshotSpan WrapWith(string prefix, string suffix, bool selectModified) {
string s = _View.GetFirstSelectionText();
var firstModified = _View.WrapWith(prefix, suffix);
if (s != null && Keyboard.Modifiers == ModifierKeys.Control && _View.FindNext(_TextSearch, s) == false) {
string s = View.GetFirstSelectionText();
var firstModified = View.WrapWith(prefix, suffix);
if (s != null && Keyboard.Modifiers == ModifierKeys.Control && View.FindNext(_TextSearch, s) == false) {
//
}
else if (selectModified) {
_View.SelectSpan(firstModified);
View.SelectSpan(firstModified);
}
return firstModified;
}
@@ -183,7 +174,7 @@ sealed class MarkdownList : ItemList

public MarkdownList(MarkdownBar bar) {
Style = SharedDictionaryManager.ItemList.Get<Style>(typeof(ItemList));
Container = bar._ListContainer;
Container = bar.ListContainer;
Header = new StackPanel {
Margin = WpfHelper.MenuItemMargin,
Children = {
@@ -201,7 +192,7 @@ public MarkdownList(MarkdownBar bar) {
Footer = new TextBlock { Margin = WpfHelper.MenuItemMargin }
.ReferenceProperty(TextBlock.ForegroundProperty, Microsoft.VisualStudio.PlatformUI.EnvironmentColors.SystemGrayTextBrushKey)
.Append(ThemeHelper.GetImage(KnownImageIds.Code))
.Append(bar._View.TextSnapshot.LineCount);
.Append(bar.View.TextSnapshot.LineCount);
_FinderBox.TextChanged += SearchCriteriaChanged;
_FinderBox.SetOnVisibleSelectAll();
_Bar = bar;
@@ -214,10 +205,10 @@ protected override void OnPreviewKeyDown(KeyEventArgs e) {
}
if (e.Key == Key.Enter) {
if (SelectedIndex == -1 && HasItems) {
((LocationItem)ItemContainerGenerator.Items[0]).GoToSource(_Bar._View);
((LocationItem)ItemContainerGenerator.Items[0]).GoToSource(_Bar.View);
}
else {
((LocationItem)SelectedItem).GoToSource(_Bar._View);
((LocationItem)SelectedItem).GoToSource(_Bar.View);
}
e.Handled = true;
}
39 changes: 39 additions & 0 deletions Codist/NaviBar/NaviBar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Windows.Controls;
using System.Windows.Input;
using Codist.Controls;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text.Editor;
using System.Windows;

namespace Codist.NaviBar
{
public abstract class NaviBar : ToolBar, INaviBar
{
protected NaviBar(IWpfTextView textView) {
View = textView;
ListContainer = View.Properties.GetOrCreateSingletonProperty(() => new ExternalAdornment(textView));
this.SetBackgroundForCrispImage(ThemeHelper.TitleBackgroundColor);
textView.Properties.AddProperty(nameof(NaviBar), this);
Resources = SharedDictionaryManager.Menu;
SetResourceReference(BackgroundProperty, VsBrushes.CommandBarMenuBackgroundGradientKey);
SetResourceReference(ForegroundProperty, VsBrushes.CommandBarTextInactiveKey);
}

public abstract void ShowActiveItemMenu();
public abstract void ShowRootItemMenu();
protected IWpfTextView View { get; }
internal ExternalAdornment ListContainer { get; }

protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e) {
var h = WpfHelper.GetParentOrSelf<DependencyObject>(e.Source as DependencyObject, o => o is IContextMenuHost) as IContextMenuHost;
if (h != null) {
h.ShowContextMenu(e);
e.Handled = true;
}
//else {
// base.OnPreviewMouseRightButtonUp(e);
//}
}
}
}

0 comments on commit 9107dc5

Please sign in to comment.