You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
10 KiB
229 lines
10 KiB
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this |
|
// software and associated documentation files (the "Software"), to deal in the Software |
|
// without restriction, including without limitation the rights to use, copy, modify, merge, |
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons |
|
// to whom the Software is furnished to do so, subject to the following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included in all copies or |
|
// substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE |
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
// DEALINGS IN THE SOFTWARE. |
|
|
|
using System.Linq; |
|
using System.Windows.Input; |
|
using ICSharpCode.WpfDesign.Designer.Controls; |
|
|
|
namespace ICSharpCode.WpfDesign.Designer |
|
{ |
|
/// <summary> |
|
/// Manages the Focus/Primary Selection using TAB for down-the-tree navigation and Shift+TAB for up-the-tree navigation. |
|
/// </summary> |
|
class FocusNavigator |
|
{ |
|
/* The Focus navigator do not involves the concept of Logical Focus or KeyBoard Focus |
|
* since nothing is getting focoused on the designer except for the DesignPanel. It just changes |
|
* the primary selection between the hierarchy of elements present on the designer. */ |
|
|
|
private readonly DesignSurface _surface; |
|
private KeyBinding _tabBinding; |
|
private KeyBinding _shiftTabBinding; |
|
|
|
public FocusNavigator(DesignSurface surface) |
|
{ |
|
this._surface=surface; |
|
} |
|
|
|
/// <summary> |
|
/// Starts the navigator on the Design surface and add bindings. |
|
/// </summary> |
|
public void Start() |
|
{ |
|
var tabFocus = new RelayCommand(this.MoveFocusForward, this.CanMoveFocusForward); |
|
var shiftTabFocus = new RelayCommand(this.MoveFocusBack, this.CanMoveFocusBack); |
|
_tabBinding = new KeyBinding(tabFocus, new KeyGesture(Key.Tab)); |
|
_shiftTabBinding = new KeyBinding(shiftTabFocus, new KeyGesture(Key.Tab, ModifierKeys.Shift)); |
|
IKeyBindingService kbs = _surface.DesignContext.Services.GetService(typeof(IKeyBindingService)) as IKeyBindingService; |
|
if (kbs != null) |
|
{ |
|
kbs.RegisterBinding(_tabBinding); |
|
kbs.RegisterBinding(_shiftTabBinding); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// De-register the bindings from the Design Surface |
|
/// </summary> |
|
public void End() |
|
{ |
|
IKeyBindingService kbs = _surface.DesignContext.Services.GetService(typeof(IKeyBindingService)) as IKeyBindingService; |
|
if (kbs != null) |
|
{ |
|
kbs.DeregisterBinding(_tabBinding); |
|
kbs.DeregisterBinding(_shiftTabBinding); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Moves the Foucus down the tree. |
|
/// </summary> |
|
void MoveFocusForward() |
|
{ |
|
var designSurface = _surface; |
|
if (designSurface != null) { |
|
var context = designSurface.DesignContext; |
|
ISelectionService selection=context.Services.Selection; |
|
DesignItem item = selection.PrimarySelection; |
|
selection.SetSelectedComponents(selection.SelectedItems, SelectionTypes.Remove); |
|
if (item != GetLastElement()) |
|
{ |
|
if (item.ContentProperty != null) |
|
{ |
|
if (item.ContentProperty.IsCollection) |
|
{ |
|
if (item.ContentProperty.CollectionElements.Count != 0) |
|
{ |
|
if (ModelTools.CanSelectComponent(item.ContentProperty.CollectionElements.First())) |
|
selection.SetSelectedComponents(new DesignItem[] { item.ContentProperty.CollectionElements.First() }, SelectionTypes.Primary); |
|
else |
|
SelectNextInPeers(item); |
|
} |
|
else |
|
SelectNextInPeers(item); |
|
} |
|
else if (item.ContentProperty.Value != null) { |
|
if (ModelTools.CanSelectComponent(item.ContentProperty.Value)) |
|
selection.SetSelectedComponents(new DesignItem[] { item.ContentProperty.Value }, SelectionTypes.Primary); |
|
else |
|
SelectNextInPeers(item); |
|
} |
|
else { |
|
SelectNextInPeers(item); |
|
} |
|
} |
|
else { |
|
SelectNextInPeers(item); |
|
} |
|
} |
|
else { //if the element was last element move focus to the root element to keep a focus cycle. |
|
selection.SetSelectedComponents(new DesignItem[] {context.RootItem}, SelectionTypes.Primary); |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Checks if focus navigation should be for down-the-tree be done. |
|
/// </summary> |
|
bool CanMoveFocusForward() |
|
{ |
|
var designSurface = _surface; |
|
if (designSurface != null) |
|
if (Keyboard.FocusedElement == designSurface._designPanel) |
|
return true; |
|
return false; |
|
} |
|
|
|
/// <summary> |
|
/// Moves focus up-the-tree. |
|
/// </summary> |
|
void MoveFocusBack() |
|
{ |
|
var designSurface = _surface; |
|
if (designSurface != null) { |
|
var context = designSurface.DesignContext; |
|
ISelectionService selection = context.Services.Selection; |
|
DesignItem item = selection.PrimarySelection; |
|
if (item != context.RootItem) |
|
{ |
|
if (item.Parent != null && item.Parent.ContentProperty.IsCollection) |
|
{ |
|
int index = item.Parent.ContentProperty.CollectionElements.IndexOf(item); |
|
if (index != 0) |
|
{ |
|
if (ModelTools.CanSelectComponent(item.Parent.ContentProperty.CollectionElements.ElementAt(index - 1))) |
|
selection.SetSelectedComponents(new DesignItem[] { item.Parent.ContentProperty.CollectionElements.ElementAt(index - 1) }, SelectionTypes.Primary); |
|
} |
|
else |
|
{ |
|
if (ModelTools.CanSelectComponent(item.Parent)) |
|
selection.SetSelectedComponents(new DesignItem[] { item.Parent }, SelectionTypes.Primary); |
|
} |
|
|
|
} |
|
else |
|
{ |
|
if (ModelTools.CanSelectComponent(item.Parent)) |
|
selection.SetSelectedComponents(new DesignItem[] { item.Parent }, SelectionTypes.Primary); |
|
} |
|
} |
|
else {// if the element was root item move focus again to the last element. |
|
selection.SetSelectedComponents(new DesignItem[] { GetLastElement() }, SelectionTypes.Primary); |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Checks if focus navigation for the up-the-tree should be done. |
|
/// </summary> |
|
bool CanMoveFocusBack() |
|
{ |
|
var designSurface = _surface; |
|
if (designSurface != null) |
|
if (Keyboard.FocusedElement == designSurface._designPanel) |
|
return true; |
|
return false; |
|
} |
|
|
|
/// <summary> |
|
/// Gets the last element in the element hierarchy. |
|
/// </summary> |
|
DesignItem GetLastElement() |
|
{ |
|
DesignItem item = _surface.DesignContext.RootItem; |
|
while (item != null && item.ContentProperty != null) |
|
{ |
|
if (item.ContentProperty.IsCollection) |
|
{ |
|
if (item.ContentProperty.CollectionElements.Count != 0) { |
|
if (ModelTools.CanSelectComponent(item.ContentProperty.CollectionElements.Last())) |
|
item = item.ContentProperty.CollectionElements.Last(); |
|
else |
|
break; |
|
} |
|
else |
|
break; |
|
} |
|
else { |
|
if (item.ContentProperty.Value != null) |
|
item = item.ContentProperty.Value; |
|
else |
|
break; |
|
} |
|
} |
|
return item; |
|
} |
|
|
|
/// <summary> |
|
/// Select the next element in the element collection if <paramref name="item"/> parent's had it's content property as collection. |
|
/// </summary> |
|
void SelectNextInPeers(DesignItem item) |
|
{ |
|
ISelectionService selection = _surface.DesignContext.Services.Selection; |
|
if (item.Parent != null && item.Parent.ContentProperty != null) |
|
{ |
|
if (item.Parent.ContentProperty.IsCollection) |
|
{ |
|
int index = item.Parent.ContentProperty.CollectionElements.IndexOf(item); |
|
if (index != item.Parent.ContentProperty.CollectionElements.Count) |
|
selection.SetSelectedComponents(new DesignItem[] { item.Parent.ContentProperty.CollectionElements.ElementAt(index + 1) }, SelectionTypes.Primary); |
|
} |
|
} |
|
} |
|
} |
|
}
|
|
|