mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-11 18:20:23 +01:00
Pushing missing changes
This commit is contained in:
62
MediaBrowser.UI.Controls/BaseModalWindow.cs
Normal file
62
MediaBrowser.UI.Controls/BaseModalWindow.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Class BaseModalWindow
|
||||
/// </summary>
|
||||
public class BaseModalWindow : BaseWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the modal.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
public void ShowModal(Window owner)
|
||||
{
|
||||
WindowStyle = WindowStyle.None;
|
||||
ResizeMode = ResizeMode.NoResize;
|
||||
ShowInTaskbar = false;
|
||||
WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
AllowsTransparency = true;
|
||||
|
||||
Width = owner.Width;
|
||||
Height = owner.Height;
|
||||
Top = owner.Top;
|
||||
Left = owner.Left;
|
||||
WindowState = owner.WindowState;
|
||||
Owner = owner;
|
||||
|
||||
ShowDialog();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [browser back].
|
||||
/// </summary>
|
||||
protected override void OnBrowserBack()
|
||||
{
|
||||
base.OnBrowserBack();
|
||||
|
||||
CloseModal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.FrameworkElement.Initialized" /> event. This method is invoked whenever <see cref="P:System.Windows.FrameworkElement.IsInitialized" /> is set to true internally.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.Windows.RoutedEventArgs" /> that contains the event data.</param>
|
||||
protected override void OnInitialized(EventArgs e)
|
||||
{
|
||||
base.OnInitialized(e);
|
||||
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the modal.
|
||||
/// </summary>
|
||||
protected virtual void CloseModal()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
MediaBrowser.UI.Controls/BaseUserControl.cs
Normal file
21
MediaBrowser.UI.Controls/BaseUserControl.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for all user controls
|
||||
/// </summary>
|
||||
public abstract class BaseUserControl : UserControl
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public virtual void OnPropertyChanged(string name)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
175
MediaBrowser.UI.Controls/BaseWindow.cs
Normal file
175
MediaBrowser.UI.Controls/BaseWindow.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for all Windows
|
||||
/// </summary>
|
||||
public abstract class BaseWindow : Window, INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when [property changed].
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Called when [property changed].
|
||||
/// </summary>
|
||||
/// <param name="info">The info.</param>
|
||||
public void OnPropertyChanged(String info)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(info));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _content scale
|
||||
/// </summary>
|
||||
private double _contentScale = 1;
|
||||
/// <summary>
|
||||
/// Gets the content scale.
|
||||
/// </summary>
|
||||
/// <value>The content scale.</value>
|
||||
public double ContentScale
|
||||
{
|
||||
get { return _contentScale; }
|
||||
private set
|
||||
{
|
||||
_contentScale = value;
|
||||
OnPropertyChanged("ContentScale");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseWindow" /> class.
|
||||
/// </summary>
|
||||
protected BaseWindow()
|
||||
: base()
|
||||
{
|
||||
SizeChanged += MainWindow_SizeChanged;
|
||||
Loaded += BaseWindowLoaded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bases the window loaded.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
|
||||
void BaseWindowLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OnLoaded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [loaded].
|
||||
/// </summary>
|
||||
protected virtual void OnLoaded()
|
||||
{
|
||||
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the SizeChanged event of the MainWindow control.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the event.</param>
|
||||
/// <param name="e">The <see cref="SizeChangedEventArgs" /> instance containing the event data.</param>
|
||||
void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ContentScale = e.NewSize.Height / 1080;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [browser back].
|
||||
/// </summary>
|
||||
protected virtual void OnBrowserBack()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [browser forward].
|
||||
/// </summary>
|
||||
protected virtual void OnBrowserForward()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Keyboard.PreviewKeyDown" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains the event data.</param>
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (IsBackPress(e))
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
if (!e.IsRepeat)
|
||||
{
|
||||
OnBrowserBack();
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsForwardPress(e))
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
if (!e.IsRepeat)
|
||||
{
|
||||
OnBrowserForward();
|
||||
}
|
||||
}
|
||||
base.OnPreviewKeyDown(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a keypress should be treated as a backward press
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="KeyEventArgs" /> instance containing the event data.</param>
|
||||
/// <returns><c>true</c> if [is back press] [the specified e]; otherwise, <c>false</c>.</returns>
|
||||
private bool IsBackPress(KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Escape)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.Key == Key.BrowserBack || e.Key == Key.Back)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.SystemKey == Key.Left && e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Alt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a keypress should be treated as a forward press
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="KeyEventArgs" /> instance containing the event data.</param>
|
||||
/// <returns><c>true</c> if [is forward press] [the specified e]; otherwise, <c>false</c>.</returns>
|
||||
private bool IsForwardPress(KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.BrowserForward)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (e.SystemKey == Key.RightAlt && e.KeyboardDevice.Modifiers.HasFlag(ModifierKeys.Alt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
49
MediaBrowser.UI.Controls/ExtendedButton.cs
Normal file
49
MediaBrowser.UI.Controls/ExtendedButton.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// This subclass simply autofocuses itself when the mouse moves over it
|
||||
/// </summary>
|
||||
public class ExtendedButton : Button
|
||||
{
|
||||
private Point? _lastMouseMovePoint;
|
||||
|
||||
/// <summary>
|
||||
/// Handles OnMouseMove to auto-select the item that's being moused over
|
||||
/// </summary>
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
var window = this.GetWindow();
|
||||
|
||||
// If the cursor is currently hidden, don't bother reacting to it
|
||||
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the last position for comparison purposes
|
||||
// Even if the mouse is not moving this event will fire as elements are showing and hiding
|
||||
var pos = e.GetPosition(window);
|
||||
|
||||
if (!_lastMouseMovePoint.HasValue)
|
||||
{
|
||||
_lastMouseMovePoint = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos == _lastMouseMovePoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastMouseMovePoint = pos;
|
||||
|
||||
Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
49
MediaBrowser.UI.Controls/ExtendedCheckbox.cs
Normal file
49
MediaBrowser.UI.Controls/ExtendedCheckbox.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends Checkbox to provide focus on mouse over
|
||||
/// </summary>
|
||||
public class ExtendedCheckbox : CheckBox
|
||||
{
|
||||
private Point? _lastMouseMovePoint;
|
||||
|
||||
/// <summary>
|
||||
/// Handles OnMouseMove to auto-select the item that's being moused over
|
||||
/// </summary>
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
var window = this.GetWindow();
|
||||
|
||||
// If the cursor is currently hidden, don't bother reacting to it
|
||||
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the last position for comparison purposes
|
||||
// Even if the mouse is not moving this event will fire as elements are showing and hiding
|
||||
var pos = e.GetPosition(window);
|
||||
|
||||
if (!_lastMouseMovePoint.HasValue)
|
||||
{
|
||||
_lastMouseMovePoint = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos == _lastMouseMovePoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastMouseMovePoint = pos;
|
||||
|
||||
Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
260
MediaBrowser.UI.Controls/ExtendedListBox.cs
Normal file
260
MediaBrowser.UI.Controls/ExtendedListBox.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends the ListBox to provide auto-focus behavior when items are moused over
|
||||
/// This also adds an ItemInvoked event that is fired when an item is clicked or invoked using the enter key
|
||||
/// </summary>
|
||||
public class ExtendedListBox : ListBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Fired when an item is clicked or invoked using the enter key
|
||||
/// </summary>
|
||||
public event EventHandler<ItemEventArgs<object>> ItemInvoked;
|
||||
|
||||
/// <summary>
|
||||
/// Called when [item invoked].
|
||||
/// </summary>
|
||||
/// <param name="boundObject">The bound object.</param>
|
||||
protected virtual void OnItemInvoked(object boundObject)
|
||||
{
|
||||
if (ItemInvoked != null)
|
||||
{
|
||||
ItemInvoked(this, new ItemEventArgs<object> { Argument = boundObject });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _auto focus
|
||||
/// </summary>
|
||||
private bool _autoFocus = true;
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating if the first list item should be auto-focused on load
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [auto focus]; otherwise, <c>false</c>.</value>
|
||||
public bool AutoFocus
|
||||
{
|
||||
get { return _autoFocus; }
|
||||
set
|
||||
{
|
||||
_autoFocus = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExtendedListBox" /> class.
|
||||
/// </summary>
|
||||
public ExtendedListBox()
|
||||
: base()
|
||||
{
|
||||
ItemContainerGenerator.StatusChanged += ItemContainerGeneratorStatusChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The mouse down object
|
||||
/// </summary>
|
||||
private object mouseDownObject;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.PreviewMouseDown" /> attached routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. The event data reports that one or more mouse buttons were pressed.</param>
|
||||
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnPreviewMouseDown(e);
|
||||
|
||||
// Get the item that the mouse down event occurred on
|
||||
mouseDownObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an unhandled <see cref="E:System.Windows.UIElement.MouseLeftButtonUp" /> routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. The event data reports that the left mouse button was released.</param>
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonUp(e);
|
||||
|
||||
// If the mouse up event occurred on the same item as the mousedown event, then fire ItemInvoked
|
||||
if (mouseDownObject != null)
|
||||
{
|
||||
var boundObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
|
||||
|
||||
if (mouseDownObject == boundObject)
|
||||
{
|
||||
mouseDownObject = null;
|
||||
OnItemInvoked(boundObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key down object
|
||||
/// </summary>
|
||||
private object keyDownObject;
|
||||
|
||||
/// <summary>
|
||||
/// Responds to the <see cref="E:System.Windows.UIElement.KeyDown" /> event.
|
||||
/// </summary>
|
||||
/// <param name="e">Provides data for <see cref="T:System.Windows.Input.KeyEventArgs" />.</param>
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
if (!e.IsRepeat)
|
||||
{
|
||||
// Get the item that the keydown event occurred on
|
||||
keyDownObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Keyboard.KeyUp" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.Windows.Input.KeyEventArgs" /> that contains the event data.</param>
|
||||
protected override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyUp(e);
|
||||
|
||||
// Fire ItemInvoked when enter is pressed on an item
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
if (!e.IsRepeat)
|
||||
{
|
||||
// If the keyup event occurred on the same item as the keydown event, then fire ItemInvoked
|
||||
if (keyDownObject != null)
|
||||
{
|
||||
var boundObject = GetBoundListItemObject((DependencyObject)e.OriginalSource);
|
||||
|
||||
if (keyDownObject == boundObject)
|
||||
{
|
||||
keyDownObject = null;
|
||||
OnItemInvoked(boundObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _last mouse move point
|
||||
/// </summary>
|
||||
private Point? _lastMouseMovePoint;
|
||||
|
||||
/// <summary>
|
||||
/// Handles OnMouseMove to auto-select the item that's being moused over
|
||||
/// </summary>
|
||||
/// <param name="e">Provides data for <see cref="T:System.Windows.Input.MouseEventArgs" />.</param>
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
var window = this.GetWindow();
|
||||
|
||||
// If the cursor is currently hidden, don't bother reacting to it
|
||||
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the last position for comparison purposes
|
||||
// Even if the mouse is not moving this event will fire as elements are showing and hiding
|
||||
var pos = e.GetPosition(window);
|
||||
|
||||
if (!_lastMouseMovePoint.HasValue)
|
||||
{
|
||||
_lastMouseMovePoint = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos == _lastMouseMovePoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastMouseMovePoint = pos;
|
||||
|
||||
var dep = (DependencyObject)e.OriginalSource;
|
||||
|
||||
while ((dep != null) && !(dep is ListBoxItem))
|
||||
{
|
||||
dep = VisualTreeHelper.GetParent(dep);
|
||||
}
|
||||
|
||||
if (dep != null)
|
||||
{
|
||||
var listBoxItem = dep as ListBoxItem;
|
||||
|
||||
if (!listBoxItem.IsFocused)
|
||||
{
|
||||
listBoxItem.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the datacontext for a given ListBoxItem
|
||||
/// </summary>
|
||||
/// <param name="dep">The dep.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
private object GetBoundListItemObject(DependencyObject dep)
|
||||
{
|
||||
while ((dep != null) && !(dep is ListBoxItem))
|
||||
{
|
||||
dep = VisualTreeHelper.GetParent(dep);
|
||||
}
|
||||
|
||||
if (dep == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ItemContainerGenerator.ItemFromContainer(dep);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Autofocuses the first list item when the list is loaded
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
|
||||
void ItemContainerGeneratorStatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated && AutoFocus)
|
||||
{
|
||||
Dispatcher.InvokeAsync(OnContainersGenerated);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [containers generated].
|
||||
/// </summary>
|
||||
void OnContainersGenerated()
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
var item = ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
item.Focus();
|
||||
ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorStatusChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
MediaBrowser.UI.Controls/ExtendedRadioButton.cs
Normal file
49
MediaBrowser.UI.Controls/ExtendedRadioButton.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends RadioButton to provide focus on mouse over, and invoke on enter press
|
||||
/// </summary>
|
||||
public class ExtendedRadioButton : RadioButton
|
||||
{
|
||||
private Point? _lastMouseMovePoint;
|
||||
|
||||
/// <summary>
|
||||
/// Handles OnMouseMove to auto-select the item that's being moused over
|
||||
/// </summary>
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
var window = this.GetWindow();
|
||||
|
||||
// If the cursor is currently hidden, don't bother reacting to it
|
||||
if (Cursor == Cursors.None || window.Cursor == Cursors.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the last position for comparison purposes
|
||||
// Even if the mouse is not moving this event will fire as elements are showing and hiding
|
||||
var pos = e.GetPosition(window);
|
||||
|
||||
if (!_lastMouseMovePoint.HasValue)
|
||||
{
|
||||
_lastMouseMovePoint = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos == _lastMouseMovePoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastMouseMovePoint = pos;
|
||||
|
||||
Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
MediaBrowser.UI.Controls/ExtendedScrollViewer.cs
Normal file
41
MediaBrowser.UI.Controls/ExtendedScrollViewer.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// This subclass solves the problem of ScrollViewers eating KeyDown for all arrow keys
|
||||
/// </summary>
|
||||
public class ExtendedScrollViewer : ScrollViewer
|
||||
{
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (e.Handled || e.OriginalSource == this)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't eat left/right if horizontal scrolling is disabled
|
||||
if (e.Key == Key.Left || e.Key == Key.Right)
|
||||
{
|
||||
if (HorizontalScrollBarVisibility == ScrollBarVisibility.Disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't eat up/down if vertical scrolling is disabled
|
||||
if (e.Key == Key.Up || e.Key == Key.Down)
|
||||
{
|
||||
if (VerticalScrollBarVisibility == ScrollBarVisibility.Disabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Let the base class do it's thing
|
||||
base.OnKeyDown(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
MediaBrowser.UI.Controls/ItemEventArgs.cs
Normal file
17
MediaBrowser.UI.Controls/ItemEventArgs.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a generic EventArgs subclass that can hold any kind of object
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class ItemEventArgs<T> : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the argument.
|
||||
/// </summary>
|
||||
/// <value>The argument.</value>
|
||||
public T Argument { get; set; }
|
||||
}
|
||||
}
|
||||
107
MediaBrowser.UI.Controls/MediaBrowser.UI.Controls.csproj
Normal file
107
MediaBrowser.UI.Controls/MediaBrowser.UI.Controls.csproj
Normal file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{1ADFE460-FD95-46FA-8871-CCCB4B62E2E8}</ProjectGuid>
|
||||
<OutputType>library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MediaBrowser.UI.Controls</RootNamespace>
|
||||
<AssemblyName>MediaBrowser.UI.Controls</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Expression.Effects">
|
||||
<HintPath>..\ThirdParty\Expression\Microsoft.Expression.Effects.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Expression.Interactions">
|
||||
<HintPath>..\ThirdParty\Expression\Microsoft.Expression.Interactions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BaseModalWindow.cs" />
|
||||
<Compile Include="BaseUserControl.cs" />
|
||||
<Compile Include="BaseWindow.cs" />
|
||||
<Compile Include="ExtendedButton.cs" />
|
||||
<Compile Include="ExtendedCheckbox.cs" />
|
||||
<Compile Include="ExtendedListBox.cs" />
|
||||
<Compile Include="ExtendedRadioButton.cs" />
|
||||
<Compile Include="ExtendedScrollViewer.cs" />
|
||||
<Compile Include="ItemEventArgs.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="ScrollingPanel.cs" />
|
||||
<Compile Include="TransitionControl.cs" />
|
||||
<Compile Include="TransitionFrame.cs" />
|
||||
<Compile Include="TreeHelper.cs" />
|
||||
<Compile Include="VirtualizingWrapPanel.cs" />
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<AppDesigner Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Themes\Generic.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
55
MediaBrowser.UI.Controls/Properties/AssemblyInfo.cs
Normal file
55
MediaBrowser.UI.Controls/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MediaBrowser.UI.Controls")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MediaBrowser.UI.Controls")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly:ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
62
MediaBrowser.UI.Controls/Properties/Resources.Designer.cs
generated
Normal file
62
MediaBrowser.UI.Controls/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,62 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18033
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MediaBrowser.UI.Controls.Properties {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if ((resourceMan == null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MediaBrowser.UI.Controls.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
MediaBrowser.UI.Controls/Properties/Resources.resx
Normal file
117
MediaBrowser.UI.Controls/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
30
MediaBrowser.UI.Controls/Properties/Settings.Designer.cs
generated
Normal file
30
MediaBrowser.UI.Controls/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18033
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MediaBrowser.UI.Controls.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
MediaBrowser.UI.Controls/Properties/Settings.settings
Normal file
7
MediaBrowser.UI.Controls/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
404
MediaBrowser.UI.Controls/ScrollingPanel.cs
Normal file
404
MediaBrowser.UI.Controls/ScrollingPanel.cs
Normal file
@@ -0,0 +1,404 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// This started from:
|
||||
/// http://www.switchonthecode.com/tutorials/wpf-tutorial-implementing-iscrollinfo
|
||||
/// Then, after implementing this, content was being displayed in stack panel like manner.
|
||||
/// I then reviewed the source code of ScrollContentPresenter and updated MeasureOverride and ArrangeOverride to match.
|
||||
/// </summary>
|
||||
public class ScrollingPanel : Grid, IScrollInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The infinite size
|
||||
/// </summary>
|
||||
private static Size InfiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||
/// <summary>
|
||||
/// The line size
|
||||
/// </summary>
|
||||
private const double LineSize = 16;
|
||||
/// <summary>
|
||||
/// The wheel size
|
||||
/// </summary>
|
||||
private const double WheelSize = 3 * LineSize;
|
||||
|
||||
/// <summary>
|
||||
/// The _ offset
|
||||
/// </summary>
|
||||
private Vector _Offset;
|
||||
/// <summary>
|
||||
/// The _ extent
|
||||
/// </summary>
|
||||
private Size _Extent;
|
||||
/// <summary>
|
||||
/// The _ viewport
|
||||
/// </summary>
|
||||
private Size _Viewport;
|
||||
|
||||
/// <summary>
|
||||
/// The _ animation length
|
||||
/// </summary>
|
||||
private TimeSpan _AnimationLength = TimeSpan.FromMilliseconds(125);
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, measures the size in layout required for child elements and determines a size for the <see cref="T:System.Windows.FrameworkElement" />-derived class.
|
||||
/// </summary>
|
||||
/// <param name="availableSize">The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
|
||||
/// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (Children == null || Children.Count == 0)
|
||||
{
|
||||
return availableSize;
|
||||
}
|
||||
|
||||
var constraint2 = availableSize;
|
||||
if (CanHorizontallyScroll)
|
||||
{
|
||||
constraint2.Width = double.PositiveInfinity;
|
||||
}
|
||||
if (CanVerticallyScroll)
|
||||
{
|
||||
constraint2.Height = double.PositiveInfinity;
|
||||
}
|
||||
|
||||
var uiElement = Children[0];
|
||||
|
||||
uiElement.Measure(constraint2);
|
||||
var size = uiElement.DesiredSize;
|
||||
|
||||
VerifyScrollData(availableSize, size);
|
||||
|
||||
size.Width = Math.Min(availableSize.Width, size.Width);
|
||||
size.Height = Math.Min(availableSize.Height, size.Height);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arranges the content of a <see cref="T:System.Windows.Controls.Grid" /> element.
|
||||
/// </summary>
|
||||
/// <param name="arrangeSize">Specifies the size this <see cref="T:System.Windows.Controls.Grid" /> element should use to arrange its child elements.</param>
|
||||
/// <returns><see cref="T:System.Windows.Size" /> that represents the arranged size of this Grid element and its children.</returns>
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
this.VerifyScrollData(arrangeSize, _Extent);
|
||||
|
||||
if (this.Children == null || this.Children.Count == 0)
|
||||
{
|
||||
return arrangeSize;
|
||||
}
|
||||
|
||||
TranslateTransform trans = null;
|
||||
|
||||
var uiElement = Children[0];
|
||||
|
||||
var finalRect = new Rect(uiElement.DesiredSize);
|
||||
|
||||
// ScrollContentPresenter sets these to 0 - current offset
|
||||
// We need to set it to zero in order to make the animation work
|
||||
finalRect.X = 0;
|
||||
finalRect.Y = 0;
|
||||
|
||||
finalRect.Width = Math.Max(finalRect.Width, arrangeSize.Width);
|
||||
finalRect.Height = Math.Max(finalRect.Height, arrangeSize.Height);
|
||||
|
||||
trans = uiElement.RenderTransform as TranslateTransform;
|
||||
|
||||
if (trans == null)
|
||||
{
|
||||
uiElement.RenderTransformOrigin = new Point(0, 0);
|
||||
trans = new TranslateTransform();
|
||||
uiElement.RenderTransform = trans;
|
||||
}
|
||||
|
||||
uiElement.Arrange(finalRect);
|
||||
|
||||
trans.BeginAnimation(TranslateTransform.XProperty,
|
||||
GetAnimation(0 - HorizontalOffset),
|
||||
HandoffBehavior.Compose);
|
||||
trans.BeginAnimation(TranslateTransform.YProperty,
|
||||
GetAnimation(0 - VerticalOffset),
|
||||
HandoffBehavior.Compose);
|
||||
|
||||
return arrangeSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the animation.
|
||||
/// </summary>
|
||||
/// <param name="toValue">To value.</param>
|
||||
/// <returns>DoubleAnimation.</returns>
|
||||
private DoubleAnimation GetAnimation(double toValue)
|
||||
{
|
||||
var animation = new DoubleAnimation(toValue, _AnimationLength);
|
||||
|
||||
animation.EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseInOut };
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
#region Movement Methods
|
||||
/// <summary>
|
||||
/// Scrolls down within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineDown()
|
||||
{ SetVerticalOffset(VerticalOffset + LineSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls up within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineUp()
|
||||
{ SetVerticalOffset(VerticalOffset - LineSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls left within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineLeft()
|
||||
{ SetHorizontalOffset(HorizontalOffset - LineSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls right within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineRight()
|
||||
{ SetHorizontalOffset(HorizontalOffset + LineSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls down within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelDown()
|
||||
{ SetVerticalOffset(VerticalOffset + WheelSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls up within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelUp()
|
||||
{ SetVerticalOffset(VerticalOffset - WheelSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls left within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelLeft()
|
||||
{ SetHorizontalOffset(HorizontalOffset - WheelSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls right within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelRight()
|
||||
{ SetHorizontalOffset(HorizontalOffset + WheelSize); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls down within content by one page.
|
||||
/// </summary>
|
||||
public void PageDown()
|
||||
{ SetVerticalOffset(VerticalOffset + ViewportHeight); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls up within content by one page.
|
||||
/// </summary>
|
||||
public void PageUp()
|
||||
{ SetVerticalOffset(VerticalOffset - ViewportHeight); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls left within content by one page.
|
||||
/// </summary>
|
||||
public void PageLeft()
|
||||
{ SetHorizontalOffset(HorizontalOffset - ViewportWidth); }
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls right within content by one page.
|
||||
/// </summary>
|
||||
public void PageRight()
|
||||
{ SetHorizontalOffset(HorizontalOffset + ViewportWidth); }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a <see cref="T:System.Windows.Controls.ScrollViewer" /> element that controls scrolling behavior.
|
||||
/// </summary>
|
||||
/// <value>The scroll owner.</value>
|
||||
/// <returns>A <see cref="T:System.Windows.Controls.ScrollViewer" /> element that controls scrolling behavior. This property has no default value.</returns>
|
||||
public ScrollViewer ScrollOwner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance can horizontally scroll; otherwise, <c>false</c>.</value>
|
||||
/// <returns>true if scrolling is possible; otherwise, false. This property has no default value.</returns>
|
||||
public bool CanHorizontallyScroll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether scrolling on the vertical axis is possible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance can vertically scroll; otherwise, <c>false</c>.</value>
|
||||
/// <returns>true if scrolling is possible; otherwise, false. This property has no default value.</returns>
|
||||
public bool CanVerticallyScroll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertical size of the extent.
|
||||
/// </summary>
|
||||
/// <value>The height of the extent.</value>
|
||||
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the vertical size of the extent.This property has no default value.</returns>
|
||||
public double ExtentHeight
|
||||
{ get { return _Extent.Height; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal size of the extent.
|
||||
/// </summary>
|
||||
/// <value>The width of the extent.</value>
|
||||
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the horizontal size of the extent. This property has no default value.</returns>
|
||||
public double ExtentWidth
|
||||
{ get { return _Extent.Width; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal offset of the scrolled content.
|
||||
/// </summary>
|
||||
/// <value>The horizontal offset.</value>
|
||||
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the horizontal offset. This property has no default value.</returns>
|
||||
public double HorizontalOffset
|
||||
{ get { return _Offset.X; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertical offset of the scrolled content.
|
||||
/// </summary>
|
||||
/// <value>The vertical offset.</value>
|
||||
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the vertical offset of the scrolled content. Valid values are between zero and the <see cref="P:System.Windows.Controls.Primitives.IScrollInfo.ExtentHeight" /> minus the <see cref="P:System.Windows.Controls.Primitives.IScrollInfo.ViewportHeight" />. This property has no default value.</returns>
|
||||
public double VerticalOffset
|
||||
{ get { return _Offset.Y; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertical size of the viewport for this content.
|
||||
/// </summary>
|
||||
/// <value>The height of the viewport.</value>
|
||||
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the vertical size of the viewport for this content. This property has no default value.</returns>
|
||||
public double ViewportHeight
|
||||
{ get { return _Viewport.Height; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the horizontal size of the viewport for this content.
|
||||
/// </summary>
|
||||
/// <value>The width of the viewport.</value>
|
||||
/// <returns>A <see cref="T:System.Double" /> that represents, in device independent pixels, the horizontal size of the viewport for this content. This property has no default value.</returns>
|
||||
public double ViewportWidth
|
||||
{ get { return _Viewport.Width; } }
|
||||
|
||||
/// <summary>
|
||||
/// Forces content to scroll until the coordinate space of a <see cref="T:System.Windows.Media.Visual" /> object is visible.
|
||||
/// </summary>
|
||||
/// <param name="visual">A <see cref="T:System.Windows.Media.Visual" /> that becomes visible.</param>
|
||||
/// <param name="rectangle">A bounding rectangle that identifies the coordinate space to make visible.</param>
|
||||
/// <returns>A <see cref="T:System.Windows.Rect" /> that is visible.</returns>
|
||||
public Rect MakeVisible(Visual visual, Rect rectangle)
|
||||
{
|
||||
if (rectangle.IsEmpty || visual == null
|
||||
|| visual == this || !base.IsAncestorOf(visual))
|
||||
{ return Rect.Empty; }
|
||||
|
||||
rectangle = visual.TransformToAncestor(this).TransformBounds(rectangle);
|
||||
|
||||
//rectangle.Inflate(50, 50);
|
||||
rectangle.Scale(1.2, 1.2);
|
||||
|
||||
Rect viewRect = new Rect(HorizontalOffset,
|
||||
VerticalOffset, ViewportWidth, ViewportHeight);
|
||||
rectangle.X += viewRect.X;
|
||||
rectangle.Y += viewRect.Y;
|
||||
|
||||
viewRect.X = CalculateNewScrollOffset(viewRect.Left,
|
||||
viewRect.Right, rectangle.Left, rectangle.Right);
|
||||
viewRect.Y = CalculateNewScrollOffset(viewRect.Top,
|
||||
viewRect.Bottom, rectangle.Top, rectangle.Bottom);
|
||||
SetHorizontalOffset(viewRect.X);
|
||||
SetVerticalOffset(viewRect.Y);
|
||||
rectangle.Intersect(viewRect);
|
||||
rectangle.X -= viewRect.X;
|
||||
rectangle.Y -= viewRect.Y;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the new scroll offset.
|
||||
/// </summary>
|
||||
/// <param name="topView">The top view.</param>
|
||||
/// <param name="bottomView">The bottom view.</param>
|
||||
/// <param name="topChild">The top child.</param>
|
||||
/// <param name="bottomChild">The bottom child.</param>
|
||||
/// <returns>System.Double.</returns>
|
||||
private static double CalculateNewScrollOffset(double topView,
|
||||
double bottomView, double topChild, double bottomChild)
|
||||
{
|
||||
bool offBottom = topChild < topView && bottomChild < bottomView;
|
||||
bool offTop = bottomChild > bottomView && topChild > topView;
|
||||
bool tooLarge = (bottomChild - topChild) > (bottomView - topView);
|
||||
|
||||
if (!offBottom && !offTop)
|
||||
{ return topView; } //Don't do anything, already in view
|
||||
|
||||
if ((offBottom && !tooLarge) || (offTop && tooLarge))
|
||||
{ return topChild; }
|
||||
|
||||
return (bottomChild - (bottomView - topView));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the scroll data.
|
||||
/// </summary>
|
||||
/// <param name="viewport">The viewport.</param>
|
||||
/// <param name="extent">The extent.</param>
|
||||
protected void VerifyScrollData(Size viewport, Size extent)
|
||||
{
|
||||
if (double.IsInfinity(viewport.Width))
|
||||
{ viewport.Width = extent.Width; }
|
||||
|
||||
if (double.IsInfinity(viewport.Height))
|
||||
{ viewport.Height = extent.Height; }
|
||||
|
||||
_Extent = extent;
|
||||
_Viewport = viewport;
|
||||
|
||||
_Offset.X = Math.Max(0,
|
||||
Math.Min(_Offset.X, ExtentWidth - ViewportWidth));
|
||||
_Offset.Y = Math.Max(0,
|
||||
Math.Min(_Offset.Y, ExtentHeight - ViewportHeight));
|
||||
|
||||
if (ScrollOwner != null)
|
||||
{ ScrollOwner.InvalidateScrollInfo(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the amount of horizontal offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">The degree to which content is horizontally offset from the containing viewport.</param>
|
||||
public void SetHorizontalOffset(double offset)
|
||||
{
|
||||
offset = Math.Max(0,
|
||||
Math.Min(offset, ExtentWidth - ViewportWidth));
|
||||
if (!offset.Equals(_Offset.X))
|
||||
{
|
||||
_Offset.X = offset;
|
||||
InvalidateArrange();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the amount of vertical offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">The degree to which content is vertically offset from the containing viewport.</param>
|
||||
public void SetVerticalOffset(double offset)
|
||||
{
|
||||
offset = Math.Max(0,
|
||||
Math.Min(offset, ExtentHeight - ViewportHeight));
|
||||
if (!offset.Equals(_Offset.Y))
|
||||
{
|
||||
_Offset.Y = offset;
|
||||
InvalidateArrange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
MediaBrowser.UI.Controls/Themes/Generic.xaml
Normal file
17
MediaBrowser.UI.Controls/Themes/Generic.xaml
Normal file
@@ -0,0 +1,17 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:MediaBrowser.UI.Controls">
|
||||
|
||||
<Style TargetType="local:TransitionControl">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:TransitionControl">
|
||||
<Grid>
|
||||
<ContentPresenter x:Name="ContentPresenter" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
147
MediaBrowser.UI.Controls/TransitionControl.cs
Normal file
147
MediaBrowser.UI.Controls/TransitionControl.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using Microsoft.Expression.Media.Effects;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// http://victorcher.blogspot.com/2012/02/wpf-transactions.html
|
||||
/// </summary>
|
||||
public class TransitionControl : ContentControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The _content presenter
|
||||
/// </summary>
|
||||
private ContentPresenter _contentPresenter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="TransitionControl" /> class.
|
||||
/// </summary>
|
||||
static TransitionControl()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(
|
||||
typeof(TransitionControl), new FrameworkPropertyMetadata(typeof(TransitionControl)));
|
||||
|
||||
ContentProperty.OverrideMetadata(
|
||||
typeof(TransitionControl), new FrameworkPropertyMetadata(OnContentPropertyChanged));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, is invoked whenever application code or internal processes call <see cref="M:System.Windows.FrameworkElement.ApplyTemplate" />.
|
||||
/// </summary>
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_contentPresenter = (ContentPresenter)Template.FindName("ContentPresenter", this);
|
||||
}
|
||||
|
||||
#region DP TransitionType
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the transition.
|
||||
/// </summary>
|
||||
/// <value>The type of the transition.</value>
|
||||
public TransitionEffect TransitionType
|
||||
{
|
||||
get { return (TransitionEffect)GetValue(TransitionTypeProperty); }
|
||||
set { SetValue(TransitionTypeProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TransitionType. This enables animation, styling, binding, etc...
|
||||
/// <summary>
|
||||
/// The transition type property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TransitionTypeProperty =
|
||||
DependencyProperty.Register("TransitionType", typeof(TransitionEffect), typeof(TransitionControl),
|
||||
new UIPropertyMetadata(new BlindsTransitionEffect()));
|
||||
|
||||
#endregion DP TransitionType
|
||||
|
||||
#region DP Transition Animation
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the transition animation.
|
||||
/// </summary>
|
||||
/// <value>The transition animation.</value>
|
||||
public DoubleAnimation TransitionAnimation
|
||||
{
|
||||
get { return (DoubleAnimation)GetValue(TransitionAnimationProperty); }
|
||||
set { SetValue(TransitionAnimationProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TransitionAnimation. This enables animation, styling, binding, etc...
|
||||
/// <summary>
|
||||
/// The transition animation property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TransitionAnimationProperty =
|
||||
DependencyProperty.Register("TransitionAnimation", typeof(DoubleAnimation), typeof(TransitionControl), new UIPropertyMetadata(null));
|
||||
|
||||
#endregion DP Transition Animation
|
||||
|
||||
/// <summary>
|
||||
/// Called when [content property changed].
|
||||
/// </summary>
|
||||
/// <param name="dp">The dp.</param>
|
||||
/// <param name="args">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
|
||||
private static void OnContentPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var oldContent = args.OldValue;
|
||||
var newContent = args.NewValue;
|
||||
|
||||
var transitionControl = (TransitionControl)dp;
|
||||
|
||||
if (DesignerProperties.GetIsInDesignMode(transitionControl))
|
||||
return;
|
||||
|
||||
if (oldContent != null && newContent != null && transitionControl.IsVisible)
|
||||
{
|
||||
transitionControl.AnimateContent(oldContent, newContent);
|
||||
}
|
||||
else if (newContent != null)
|
||||
{
|
||||
transitionControl.Content = newContent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates the content.
|
||||
/// </summary>
|
||||
/// <param name="oldContent">The old content.</param>
|
||||
/// <param name="newContent">The new content.</param>
|
||||
private void AnimateContent(object oldContent, object newContent)
|
||||
{
|
||||
FrameworkElement oldContentVisual;
|
||||
|
||||
try
|
||||
{
|
||||
oldContentVisual = VisualTreeHelper.GetChild(_contentPresenter, 0) as FrameworkElement;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var transitionEffect = TransitionType;
|
||||
|
||||
if (transitionEffect == null)
|
||||
{
|
||||
_contentPresenter.Content = newContent;
|
||||
return;
|
||||
}
|
||||
|
||||
var da = TransitionAnimation;
|
||||
da.From = 0;
|
||||
da.To = 1;
|
||||
da.FillBehavior = FillBehavior.HoldEnd;
|
||||
|
||||
transitionEffect.OldImage = new VisualBrush(oldContentVisual);
|
||||
transitionEffect.BeginAnimation(TransitionEffect.ProgressProperty, da);
|
||||
|
||||
_contentPresenter.Effect = transitionEffect;
|
||||
_contentPresenter.Content = newContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
194
MediaBrowser.UI.Controls/TransitionFrame.cs
Normal file
194
MediaBrowser.UI.Controls/TransitionFrame.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
using Microsoft.Expression.Media.Effects;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Class TransitionFrame
|
||||
/// </summary>
|
||||
public class TransitionFrame : Frame
|
||||
{
|
||||
/// <summary>
|
||||
/// The _content presenter
|
||||
/// </summary>
|
||||
private ContentPresenter _contentPresenter = null;
|
||||
|
||||
#region DP TransitionType
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the transition.
|
||||
/// </summary>
|
||||
/// <value>The type of the transition.</value>
|
||||
public TransitionEffect TransitionType
|
||||
{
|
||||
get { return (TransitionEffect)GetValue(TransitionTypeProperty); }
|
||||
set { SetValue(TransitionTypeProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TransitionType. This enables animation, styling, binding, etc...
|
||||
/// <summary>
|
||||
/// The transition type property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TransitionTypeProperty =
|
||||
DependencyProperty.Register("TransitionType", typeof(TransitionEffect), typeof(TransitionFrame),
|
||||
new UIPropertyMetadata(new BlindsTransitionEffect()));
|
||||
|
||||
#endregion DP TransitionType
|
||||
|
||||
#region DP Transition Animation
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the transition animation.
|
||||
/// </summary>
|
||||
/// <value>The transition animation.</value>
|
||||
public DoubleAnimation TransitionAnimation
|
||||
{
|
||||
get { return (DoubleAnimation)GetValue(TransitionAnimationProperty); }
|
||||
set { SetValue(TransitionAnimationProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TransitionAnimation. This enables animation, styling, binding, etc...
|
||||
/// <summary>
|
||||
/// The transition animation property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TransitionAnimationProperty =
|
||||
DependencyProperty.Register("TransitionAnimation", typeof(DoubleAnimation), typeof(TransitionFrame), new UIPropertyMetadata(null));
|
||||
|
||||
#endregion DP Transition Animation
|
||||
|
||||
/// <summary>
|
||||
/// Called when the template generation for the visual tree is created.
|
||||
/// </summary>
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
// get a reference to the frame's content presenter
|
||||
// this is the element we will fade in and out
|
||||
_contentPresenter = GetTemplateChild("PART_FrameCP") as ContentPresenter;
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates the content.
|
||||
/// </summary>
|
||||
/// <param name="navigationAction">The navigation action.</param>
|
||||
/// <param name="checkContent">if set to <c>true</c> [check content].</param>
|
||||
/// <param name="isBack">if set to <c>true</c> [is back].</param>
|
||||
private void AnimateContent(Action navigationAction, bool checkContent = true, bool isBack = false)
|
||||
{
|
||||
if (TransitionType == null || (checkContent && Content == null))
|
||||
{
|
||||
CommandBindings.Clear();
|
||||
navigationAction();
|
||||
CommandBindings.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
var oldContentVisual = this as FrameworkElement;
|
||||
|
||||
_contentPresenter.IsHitTestVisible = false;
|
||||
|
||||
var da = TransitionAnimation.Clone();
|
||||
da.From = 0;
|
||||
da.To = 1;
|
||||
da.FillBehavior = FillBehavior.HoldEnd;
|
||||
|
||||
var transitionEffect = TransitionType.Clone() as TransitionEffect;
|
||||
|
||||
if (isBack)
|
||||
{
|
||||
ReverseDirection(transitionEffect);
|
||||
}
|
||||
|
||||
transitionEffect.OldImage = new VisualBrush(oldContentVisual);
|
||||
transitionEffect.BeginAnimation(TransitionEffect.ProgressProperty, da);
|
||||
|
||||
_contentPresenter.Effect = transitionEffect;
|
||||
_contentPresenter.IsHitTestVisible = true;
|
||||
|
||||
// Remove base class bindings to remote buttons
|
||||
CommandBindings.Clear();
|
||||
|
||||
navigationAction();
|
||||
|
||||
CommandBindings.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates the with transition.
|
||||
/// </summary>
|
||||
/// <param name="page">The page.</param>
|
||||
public void NavigateWithTransition(Page page)
|
||||
{
|
||||
AnimateContent(() => Navigate(page));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigates the with transition.
|
||||
/// </summary>
|
||||
/// <param name="page">The page.</param>
|
||||
public void NavigateWithTransition(Uri page)
|
||||
{
|
||||
AnimateContent(() => Navigate(page));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Goes the back with transition.
|
||||
/// </summary>
|
||||
public void GoBackWithTransition()
|
||||
{
|
||||
if (CanGoBack)
|
||||
{
|
||||
AnimateContent(GoBack, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Goes the forward with transition.
|
||||
/// </summary>
|
||||
public void GoForwardWithTransition()
|
||||
{
|
||||
if (CanGoForward)
|
||||
{
|
||||
AnimateContent(GoForward, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the direction.
|
||||
/// </summary>
|
||||
/// <param name="transitionEffect">The transition effect.</param>
|
||||
private void ReverseDirection(TransitionEffect transitionEffect)
|
||||
{
|
||||
var circleRevealTransitionEffect = transitionEffect as CircleRevealTransitionEffect;
|
||||
|
||||
if (circleRevealTransitionEffect != null)
|
||||
{
|
||||
circleRevealTransitionEffect.Reverse = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var slideInTransitionEffect = transitionEffect as SlideInTransitionEffect;
|
||||
if (slideInTransitionEffect != null)
|
||||
{
|
||||
if (slideInTransitionEffect.SlideDirection == SlideDirection.RightToLeft)
|
||||
{
|
||||
slideInTransitionEffect.SlideDirection = SlideDirection.LeftToRight;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var wipeTransitionEffect = transitionEffect as WipeTransitionEffect;
|
||||
if (wipeTransitionEffect != null)
|
||||
{
|
||||
if (wipeTransitionEffect.WipeDirection == WipeDirection.RightToLeft)
|
||||
{
|
||||
wipeTransitionEffect.WipeDirection = WipeDirection.LeftToRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
321
MediaBrowser.UI.Controls/TreeHelper.cs
Normal file
321
MediaBrowser.UI.Controls/TreeHelper.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper methods for UI-related tasks.
|
||||
/// </summary>
|
||||
public static class TreeHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the window.
|
||||
/// </summary>
|
||||
/// <param name="element">The element.</param>
|
||||
/// <returns>Window.</returns>
|
||||
/// <value>The window.</value>
|
||||
public static Window GetWindow(this FrameworkElement element)
|
||||
{
|
||||
return element.ParentOfType<Window>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent.
|
||||
/// </summary>
|
||||
/// <param name="element">The element.</param>
|
||||
/// <returns>DependencyObject.</returns>
|
||||
private static DependencyObject GetParent(this DependencyObject element)
|
||||
{
|
||||
DependencyObject parent = VisualTreeHelper.GetParent(element);
|
||||
if (parent == null)
|
||||
{
|
||||
FrameworkElement frameworkElement = element as FrameworkElement;
|
||||
if (frameworkElement != null)
|
||||
{
|
||||
parent = frameworkElement.Parent;
|
||||
}
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parents.
|
||||
/// </summary>
|
||||
/// <param name="element">The element.</param>
|
||||
/// <returns>IEnumerable{DependencyObject}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">element</exception>
|
||||
public static IEnumerable<DependencyObject> GetParents(this DependencyObject element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
while ((element = element.GetParent()) != null)
|
||||
{
|
||||
yield return element;
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parents the type of the of.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="element">The element.</param>
|
||||
/// <returns>``0.</returns>
|
||||
public static T ParentOfType<T>(this DependencyObject element) where T : DependencyObject
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
return element.GetParents().OfType<T>().FirstOrDefault<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a Child of a given item in the visual tree.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the queried item.</typeparam>
|
||||
/// <param name="parent">A direct parent of the queried item.</param>
|
||||
/// <param name="childName">x:Name or Name of child.</param>
|
||||
/// <returns>The first parent item that matches the submitted type parameter.
|
||||
/// If not matching item can be found,
|
||||
/// a null parent is being returned.</returns>
|
||||
public static T FindChild<T>(DependencyObject parent, string childName)
|
||||
where T : DependencyObject
|
||||
{
|
||||
// Confirm parent and childName are valid.
|
||||
if (parent == null) return null;
|
||||
|
||||
T foundChild = null;
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(parent, i);
|
||||
// If the child is not of the request child type child
|
||||
T childType = child as T;
|
||||
if (childType == null)
|
||||
{
|
||||
// recursively drill down the tree
|
||||
foundChild = FindChild<T>(child, childName);
|
||||
|
||||
// If the child is found, break so we do not overwrite the found child.
|
||||
if (foundChild != null) break;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(childName))
|
||||
{
|
||||
var frameworkElement = child as FrameworkElement;
|
||||
// If the child's name is set for search
|
||||
if (frameworkElement != null && frameworkElement.Name == childName)
|
||||
{
|
||||
// if the child's name is of the request name
|
||||
foundChild = (T)child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// child element found.
|
||||
foundChild = (T)child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundChild;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the visual child.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="referenceVisual">The reference visual.</param>
|
||||
/// <returns>``0.</returns>
|
||||
public static T GetVisualChild<T>(this Visual referenceVisual) where T : Visual
|
||||
{
|
||||
Visual child = null;
|
||||
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
|
||||
{
|
||||
child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
|
||||
if (child != null && (child.GetType() == typeof(T)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (child != null)
|
||||
{
|
||||
child = GetVisualChild<T>(child);
|
||||
if (child != null && (child.GetType() == typeof(T)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return child as T;
|
||||
}
|
||||
|
||||
#region find parent
|
||||
|
||||
/// <summary>
|
||||
/// Finds a parent of a given item on the visual tree.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the queried item.</typeparam>
|
||||
/// <param name="child">A direct or indirect child of the
|
||||
/// queried item.</param>
|
||||
/// <returns>The first parent item that matches the submitted
|
||||
/// type parameter. If not matching item can be found, a null
|
||||
/// reference is being returned.</returns>
|
||||
public static T TryFindParent<T>(this DependencyObject child)
|
||||
where T : DependencyObject
|
||||
{
|
||||
//get parent item
|
||||
DependencyObject parentObject = GetParentObject(child);
|
||||
|
||||
//we've reached the end of the tree
|
||||
if (parentObject == null) return null;
|
||||
|
||||
//check if the parent matches the type we're looking for
|
||||
T parent = parentObject as T;
|
||||
if (parent != null)
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
//use recursion to proceed with next level
|
||||
return TryFindParent<T>(parentObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is an alternative to WPF's
|
||||
/// <see cref="VisualTreeHelper.GetParent" /> method, which also
|
||||
/// supports content elements. Keep in mind that for content element,
|
||||
/// this method falls back to the logical tree of the element!
|
||||
/// </summary>
|
||||
/// <param name="child">The item to be processed.</param>
|
||||
/// <returns>The submitted item's parent, if available. Otherwise
|
||||
/// null.</returns>
|
||||
public static DependencyObject GetParentObject(this DependencyObject child)
|
||||
{
|
||||
if (child == null) return null;
|
||||
|
||||
//handle content elements separately
|
||||
ContentElement contentElement = child as ContentElement;
|
||||
if (contentElement != null)
|
||||
{
|
||||
DependencyObject parent = ContentOperations.GetParent(contentElement);
|
||||
if (parent != null) return parent;
|
||||
|
||||
FrameworkContentElement fce = contentElement as FrameworkContentElement;
|
||||
return fce != null ? fce.Parent : null;
|
||||
}
|
||||
|
||||
//also try searching for parent in framework elements (such as DockPanel, etc)
|
||||
FrameworkElement frameworkElement = child as FrameworkElement;
|
||||
if (frameworkElement != null)
|
||||
{
|
||||
DependencyObject parent = frameworkElement.Parent;
|
||||
if (parent != null) return parent;
|
||||
}
|
||||
|
||||
//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
|
||||
return VisualTreeHelper.GetParent(child);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region find children
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes both visual and logical tree in order to find all elements of a given
|
||||
/// type that are descendants of the <paramref name="source" /> item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the queried items.</typeparam>
|
||||
/// <param name="source">The root element that marks the source of the search. If the
|
||||
/// source is already of the requested type, it will not be included in the result.</param>
|
||||
/// <returns>All descendants of <paramref name="source" /> that match the requested type.</returns>
|
||||
public static IEnumerable<T> FindChildren<T>(this DependencyObject source) where T : DependencyObject
|
||||
{
|
||||
if (source != null)
|
||||
{
|
||||
var childs = GetChildObjects(source);
|
||||
foreach (DependencyObject child in childs)
|
||||
{
|
||||
//analyze if children match the requested type
|
||||
if (child is T)
|
||||
{
|
||||
yield return (T)child;
|
||||
}
|
||||
|
||||
//recurse tree
|
||||
foreach (T descendant in FindChildren<T>(child))
|
||||
{
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method is an alternative to WPF's
|
||||
/// <see cref="VisualTreeHelper.GetChild" /> method, which also
|
||||
/// supports content elements. Keep in mind that for content elements,
|
||||
/// this method falls back to the logical tree of the element.
|
||||
/// </summary>
|
||||
/// <param name="parent">The item to be processed.</param>
|
||||
/// <returns>The submitted item's child elements, if available.</returns>
|
||||
public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent)
|
||||
{
|
||||
if (parent == null) yield break;
|
||||
|
||||
if (parent is ContentElement || parent is FrameworkElement)
|
||||
{
|
||||
//use the logical tree for content / framework elements
|
||||
foreach (object obj in LogicalTreeHelper.GetChildren(parent))
|
||||
{
|
||||
var depObj = obj as DependencyObject;
|
||||
if (depObj != null) yield return (DependencyObject)obj;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//use the visual tree per default
|
||||
int count = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return VisualTreeHelper.GetChild(parent, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region find from point
|
||||
|
||||
/// <summary>
|
||||
/// Tries to locate a given item within the visual tree,
|
||||
/// starting with the dependency object at a given position.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the element to be found
|
||||
/// on the visual tree of the element at the given location.</typeparam>
|
||||
/// <param name="reference">The main element which is used to perform
|
||||
/// hit testing.</param>
|
||||
/// <param name="point">The position to be evaluated on the origin.</param>
|
||||
/// <returns>``0.</returns>
|
||||
public static T TryFindFromPoint<T>(UIElement reference, Point point)
|
||||
where T : DependencyObject
|
||||
{
|
||||
DependencyObject element = reference.InputHitTest(point) as DependencyObject;
|
||||
|
||||
if (element == null) return null;
|
||||
|
||||
if (element is T) return (T)element;
|
||||
|
||||
return TryFindParent<T>(element);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
735
MediaBrowser.UI.Controls/VirtualizingWrapPanel.cs
Normal file
735
MediaBrowser.UI.Controls/VirtualizingWrapPanel.cs
Normal file
@@ -0,0 +1,735 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace MediaBrowser.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// http://www.codeproject.com/Articles/75847/Virtualizing-WrapPanel
|
||||
/// Positions child elements in sequential position from left to right, breaking content
|
||||
/// to the next line at the edge of the containing box. Subsequent ordering happens
|
||||
/// sequentially from top to bottom or from right to left, depending on the value of
|
||||
/// the Orientation property.
|
||||
/// </summary>
|
||||
[DefaultProperty("Orientation")]
|
||||
public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies the ItemHeight dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(100.0, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
|
||||
/// <summary>
|
||||
/// Identifies the Orientation dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(VirtualizingWrapPanel), new PropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
|
||||
/// <summary>
|
||||
/// Identifies the ItemWidth dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(100.0, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
|
||||
/// <summary>
|
||||
/// Identifies the ScrollStep dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ScrollStepProperty = DependencyProperty.Register("ScrollStep", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(10.0, new PropertyChangedCallback(VirtualizingWrapPanel.OnAppearancePropertyChanged)));
|
||||
private bool canHorizontallyScroll;
|
||||
private bool canVerticallyScroll;
|
||||
private Size contentExtent = new Size(0.0, 0.0);
|
||||
private Point contentOffset = default(Point);
|
||||
private ScrollViewer scrollOwner;
|
||||
private Size viewport = new Size(0.0, 0.0);
|
||||
private int previousItemCount;
|
||||
/// <summary>
|
||||
/// Gets or sets a value that specifies the height of all items that are
|
||||
/// contained within a VirtualizingWrapPanel. This is a dependency property.
|
||||
/// </summary>
|
||||
public double ItemHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)base.GetValue(VirtualizingWrapPanel.ItemHeightProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetValue(VirtualizingWrapPanel.ItemHeightProperty, value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a value that specifies the width of all items that are
|
||||
/// contained within a VirtualizingWrapPanel. This is a dependency property.
|
||||
/// </summary>
|
||||
public double ItemWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)base.GetValue(VirtualizingWrapPanel.ItemWidthProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetValue(VirtualizingWrapPanel.ItemWidthProperty, value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a value that specifies the dimension in which child
|
||||
/// content is arranged. This is a dependency property.
|
||||
/// </summary>
|
||||
public Orientation Orientation
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Orientation)base.GetValue(VirtualizingWrapPanel.OrientationProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetValue(VirtualizingWrapPanel.OrientationProperty, value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible.
|
||||
/// </summary>
|
||||
public bool CanHorizontallyScroll
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.canHorizontallyScroll;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.canHorizontallyScroll != value)
|
||||
{
|
||||
this.canHorizontallyScroll = value;
|
||||
base.InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether scrolling on the vertical axis is possible.
|
||||
/// </summary>
|
||||
public bool CanVerticallyScroll
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.canVerticallyScroll;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (this.canVerticallyScroll != value)
|
||||
{
|
||||
this.canVerticallyScroll = value;
|
||||
base.InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a ScrollViewer element that controls scrolling behavior.
|
||||
/// </summary>
|
||||
public ScrollViewer ScrollOwner
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.scrollOwner;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.scrollOwner = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the vertical offset of the scrolled content.
|
||||
/// </summary>
|
||||
public double VerticalOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.contentOffset.Y;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the vertical size of the viewport for this content.
|
||||
/// </summary>
|
||||
public double ViewportHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.viewport.Height;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the horizontal size of the viewport for this content.
|
||||
/// </summary>
|
||||
public double ViewportWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.viewport.Width;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a value for mouse wheel scroll step.
|
||||
/// </summary>
|
||||
public double ScrollStep
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)base.GetValue(VirtualizingWrapPanel.ScrollStepProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SetValue(VirtualizingWrapPanel.ScrollStepProperty, value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the vertical size of the extent.
|
||||
/// </summary>
|
||||
public double ExtentHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.contentExtent.Height;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the horizontal size of the extent.
|
||||
/// </summary>
|
||||
public double ExtentWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.contentExtent.Width;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the horizontal offset of the scrolled content.
|
||||
/// </summary>
|
||||
public double HorizontalOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.contentOffset.X;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls down within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineDown()
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset + this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls left within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineLeft()
|
||||
{
|
||||
this.SetHorizontalOffset(this.HorizontalOffset - this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls right within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineRight()
|
||||
{
|
||||
this.SetHorizontalOffset(this.HorizontalOffset + this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls up within content by one logical unit.
|
||||
/// </summary>
|
||||
public void LineUp()
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset - this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Forces content to scroll until the coordinate space of a Visual object is visible.
|
||||
/// </summary>
|
||||
public Rect MakeVisible(Visual visual, Rect rectangle)
|
||||
{
|
||||
this.MakeVisible(visual as UIElement);
|
||||
return rectangle;
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls down within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelDown()
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset + this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls left within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelLeft()
|
||||
{
|
||||
this.SetHorizontalOffset(this.HorizontalOffset - this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls right within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelRight()
|
||||
{
|
||||
this.SetHorizontalOffset(this.HorizontalOffset + this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls up within content after a user clicks the wheel button on a mouse.
|
||||
/// </summary>
|
||||
public void MouseWheelUp()
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset - this.ScrollStep);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls down within content by one page.
|
||||
/// </summary>
|
||||
public void PageDown()
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset + this.ViewportHeight);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls left within content by one page.
|
||||
/// </summary>
|
||||
public void PageLeft()
|
||||
{
|
||||
this.SetHorizontalOffset(this.HorizontalOffset - this.ViewportHeight);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls right within content by one page.
|
||||
/// </summary>
|
||||
public void PageRight()
|
||||
{
|
||||
this.SetHorizontalOffset(this.HorizontalOffset + this.ViewportHeight);
|
||||
}
|
||||
/// <summary>
|
||||
/// Scrolls up within content by one page.
|
||||
/// </summary>
|
||||
public void PageUp()
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset - this.viewport.Height);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the amount of vertical offset.
|
||||
/// </summary>
|
||||
public void SetVerticalOffset(double offset)
|
||||
{
|
||||
if (offset < 0.0 || this.ViewportHeight >= this.ExtentHeight)
|
||||
{
|
||||
offset = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offset + this.ViewportHeight >= this.ExtentHeight)
|
||||
{
|
||||
offset = this.ExtentHeight - this.ViewportHeight;
|
||||
}
|
||||
}
|
||||
this.contentOffset.Y = offset;
|
||||
if (this.ScrollOwner != null)
|
||||
{
|
||||
this.ScrollOwner.InvalidateScrollInfo();
|
||||
}
|
||||
base.InvalidateMeasure();
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the amount of horizontal offset.
|
||||
/// </summary>
|
||||
public void SetHorizontalOffset(double offset)
|
||||
{
|
||||
if (offset < 0.0 || this.ViewportWidth >= this.ExtentWidth)
|
||||
{
|
||||
offset = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offset + this.ViewportWidth >= this.ExtentWidth)
|
||||
{
|
||||
offset = this.ExtentWidth - this.ViewportWidth;
|
||||
}
|
||||
}
|
||||
this.contentOffset.X = offset;
|
||||
if (this.ScrollOwner != null)
|
||||
{
|
||||
this.ScrollOwner.InvalidateScrollInfo();
|
||||
}
|
||||
base.InvalidateMeasure();
|
||||
}
|
||||
/// <summary>
|
||||
/// Note: Works only for vertical.
|
||||
/// </summary>
|
||||
internal void PageLast()
|
||||
{
|
||||
this.contentOffset.Y = this.ExtentHeight;
|
||||
if (this.ScrollOwner != null)
|
||||
{
|
||||
this.ScrollOwner.InvalidateScrollInfo();
|
||||
}
|
||||
base.InvalidateMeasure();
|
||||
}
|
||||
/// <summary>
|
||||
/// Note: Works only for vertical.
|
||||
/// </summary>
|
||||
internal void PageFirst()
|
||||
{
|
||||
this.contentOffset.Y = 0.0;
|
||||
if (this.ScrollOwner != null)
|
||||
{
|
||||
this.ScrollOwner.InvalidateScrollInfo();
|
||||
}
|
||||
base.InvalidateMeasure();
|
||||
}
|
||||
/// <summary>
|
||||
/// When items are removed, remove the corresponding UI if necessary.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args)
|
||||
{
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
base.RemoveInternalChildRange(args.Position.Index, args.ItemUICount);
|
||||
return;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
{
|
||||
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
|
||||
if (itemsControl != null)
|
||||
{
|
||||
if (this.previousItemCount != itemsControl.Items.Count)
|
||||
{
|
||||
if (this.Orientation == Orientation.Horizontal)
|
||||
{
|
||||
this.SetVerticalOffset(0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetHorizontalOffset(0.0);
|
||||
}
|
||||
}
|
||||
this.previousItemCount = itemsControl.Items.Count;
|
||||
}
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Measure the children.
|
||||
/// </summary>
|
||||
/// <param name="availableSize">The available size.</param>
|
||||
/// <returns>The desired size.</returns>
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
this.InvalidateScrollInfo(availableSize);
|
||||
int firstVisibleIndex;
|
||||
int lastVisibleIndex;
|
||||
if (this.Orientation == Orientation.Horizontal)
|
||||
{
|
||||
this.GetVerticalVisibleRange(out firstVisibleIndex, out lastVisibleIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.GetHorizontalVisibleRange(out firstVisibleIndex, out lastVisibleIndex);
|
||||
}
|
||||
UIElementCollection children = base.Children;
|
||||
IItemContainerGenerator generator = base.ItemContainerGenerator;
|
||||
if (generator != null)
|
||||
{
|
||||
GeneratorPosition startPos = generator.GeneratorPositionFromIndex(firstVisibleIndex);
|
||||
int childIndex = (startPos.Offset == 0) ? startPos.Index : (startPos.Index + 1);
|
||||
if (childIndex == -1)
|
||||
{
|
||||
this.RefreshOffset();
|
||||
}
|
||||
using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
|
||||
{
|
||||
int itemIndex = firstVisibleIndex;
|
||||
while (itemIndex <= lastVisibleIndex)
|
||||
{
|
||||
bool newlyRealized;
|
||||
UIElement child = generator.GenerateNext(out newlyRealized) as UIElement;
|
||||
if (newlyRealized)
|
||||
{
|
||||
if (childIndex >= children.Count)
|
||||
{
|
||||
base.AddInternalChild(child);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.InsertInternalChild(childIndex, child);
|
||||
}
|
||||
generator.PrepareItemContainer(child);
|
||||
}
|
||||
if (child != null)
|
||||
{
|
||||
child.Measure(new Size(this.ItemWidth, this.ItemHeight));
|
||||
}
|
||||
itemIndex++;
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
this.CleanUpChildren(firstVisibleIndex, lastVisibleIndex);
|
||||
}
|
||||
if (IsCloseTo(availableSize.Height, double.PositiveInfinity) || IsCloseTo(availableSize.Width, double.PositiveInfinity))
|
||||
{
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
|
||||
var itemsControl = ItemsControl.GetItemsOwner(this);
|
||||
var numItems = itemsControl.Items.Count;
|
||||
|
||||
var width = availableSize.Width;
|
||||
var height = availableSize.Height;
|
||||
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
var numRows = Math.Floor(availableSize.Height / ItemHeight);
|
||||
|
||||
height = numRows * ItemHeight;
|
||||
|
||||
var requiredColumns = Math.Ceiling(numItems / numRows);
|
||||
|
||||
width = Math.Min(requiredColumns * ItemWidth, width);
|
||||
}
|
||||
else
|
||||
{
|
||||
var numColumns = Math.Floor(availableSize.Width / ItemWidth);
|
||||
|
||||
width = numColumns * ItemWidth;
|
||||
|
||||
//if (numItems > 0 && numItems < numColumns)
|
||||
//{
|
||||
// width = Math.Min(numColumns, numItems) * ItemWidth;
|
||||
//}
|
||||
|
||||
var requiredRows = Math.Ceiling(numItems / numColumns);
|
||||
|
||||
height = Math.Min(requiredRows * ItemHeight, height);
|
||||
}
|
||||
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arranges the children.
|
||||
/// </summary>
|
||||
/// <param name="finalSize">The available size.</param>
|
||||
/// <returns>The used size.</returns>
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
bool isHorizontal = this.Orientation == Orientation.Horizontal;
|
||||
this.InvalidateScrollInfo(finalSize);
|
||||
int i = 0;
|
||||
foreach (object item in base.Children)
|
||||
{
|
||||
this.ArrangeChild(isHorizontal, finalSize, i++, item as UIElement);
|
||||
}
|
||||
return finalSize;
|
||||
}
|
||||
private static void OnAppearancePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
UIElement panel = d as UIElement;
|
||||
if (panel != null)
|
||||
{
|
||||
panel.InvalidateMeasure();
|
||||
}
|
||||
}
|
||||
private void MakeVisible(UIElement element)
|
||||
{
|
||||
ItemContainerGenerator generator = base.ItemContainerGenerator.GetItemContainerGeneratorForPanel(this);
|
||||
if (element != null && generator != null)
|
||||
{
|
||||
for (int itemIndex = generator.IndexFromContainer(element); itemIndex == -1; itemIndex = generator.IndexFromContainer(element))
|
||||
{
|
||||
element = element.ParentOfType<UIElement>();
|
||||
}
|
||||
ScrollViewer scrollViewer = element.ParentOfType<ScrollViewer>();
|
||||
if (scrollViewer != null)
|
||||
{
|
||||
GeneralTransform elementTransform = element.TransformToVisual(scrollViewer);
|
||||
Rect elementRectangle = elementTransform.TransformBounds(new Rect(new Point(0.0, 0.0), element.RenderSize));
|
||||
|
||||
if (this.Orientation == Orientation.Horizontal)
|
||||
{
|
||||
var padding = ItemHeight / 3;
|
||||
|
||||
if (elementRectangle.Bottom > this.ViewportHeight)
|
||||
{
|
||||
this.SetVerticalOffset(this.contentOffset.Y + elementRectangle.Bottom - this.ViewportHeight + padding);
|
||||
return;
|
||||
}
|
||||
if (elementRectangle.Top < 0.0)
|
||||
{
|
||||
this.SetVerticalOffset(this.contentOffset.Y + elementRectangle.Top - padding);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var padding = ItemWidth / 3;
|
||||
|
||||
if (elementRectangle.Right > this.ViewportWidth)
|
||||
{
|
||||
this.SetHorizontalOffset(this.contentOffset.X + elementRectangle.Right - this.ViewportWidth + padding);
|
||||
return;
|
||||
}
|
||||
if (elementRectangle.Left < 0.0)
|
||||
{
|
||||
this.SetHorizontalOffset(this.contentOffset.X + elementRectangle.Left - padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void GetVerticalVisibleRange(out int firstVisibleItemIndex, out int lastVisibleItemIndex)
|
||||
{
|
||||
int childrenPerRow = this.GetVerticalChildrenCountPerRow(this.contentExtent);
|
||||
firstVisibleItemIndex = (int)Math.Floor(this.VerticalOffset / this.ItemHeight) * childrenPerRow;
|
||||
lastVisibleItemIndex = (int)Math.Ceiling((this.VerticalOffset + this.ViewportHeight) / this.ItemHeight) * childrenPerRow - 1;
|
||||
this.AdjustVisibleRange(ref firstVisibleItemIndex, ref lastVisibleItemIndex);
|
||||
}
|
||||
private void GetHorizontalVisibleRange(out int firstVisibleItemIndex, out int lastVisibleItemIndex)
|
||||
{
|
||||
int childrenPerRow = this.GetHorizontalChildrenCountPerRow(this.contentExtent);
|
||||
firstVisibleItemIndex = (int)Math.Floor(this.HorizontalOffset / this.ItemWidth) * childrenPerRow;
|
||||
lastVisibleItemIndex = (int)Math.Ceiling((this.HorizontalOffset + this.ViewportWidth) / this.ItemWidth) * childrenPerRow - 1;
|
||||
this.AdjustVisibleRange(ref firstVisibleItemIndex, ref lastVisibleItemIndex);
|
||||
}
|
||||
private void AdjustVisibleRange(ref int firstVisibleItemIndex, ref int lastVisibleItemIndex)
|
||||
{
|
||||
firstVisibleItemIndex--;
|
||||
lastVisibleItemIndex++;
|
||||
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
|
||||
if (itemsControl != null)
|
||||
{
|
||||
if (firstVisibleItemIndex < 0)
|
||||
{
|
||||
firstVisibleItemIndex = 0;
|
||||
}
|
||||
if (lastVisibleItemIndex >= itemsControl.Items.Count)
|
||||
{
|
||||
lastVisibleItemIndex = itemsControl.Items.Count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void CleanUpChildren(int minIndex, int maxIndex)
|
||||
{
|
||||
UIElementCollection children = base.Children;
|
||||
IItemContainerGenerator generator = base.ItemContainerGenerator;
|
||||
for (int i = children.Count - 1; i >= 0; i--)
|
||||
{
|
||||
GeneratorPosition pos = new GeneratorPosition(i, 0);
|
||||
int itemIndex = generator.IndexFromGeneratorPosition(pos);
|
||||
if (itemIndex < minIndex || itemIndex > maxIndex)
|
||||
{
|
||||
generator.Remove(pos, 1);
|
||||
base.RemoveInternalChildRange(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ArrangeChild(bool isHorizontal, Size finalSize, int index, UIElement child)
|
||||
{
|
||||
if (child == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int count = isHorizontal ? this.GetVerticalChildrenCountPerRow(finalSize) : this.GetHorizontalChildrenCountPerRow(finalSize);
|
||||
int itemIndex = base.ItemContainerGenerator.IndexFromGeneratorPosition(new GeneratorPosition(index, 0));
|
||||
int row = isHorizontal ? (itemIndex / count) : (itemIndex % count);
|
||||
int column = isHorizontal ? (itemIndex % count) : (itemIndex / count);
|
||||
Rect rect = new Rect((double)column * this.ItemWidth, (double)row * this.ItemHeight, this.ItemWidth, this.ItemHeight);
|
||||
if (isHorizontal)
|
||||
{
|
||||
rect.Y -= this.VerticalOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.X -= this.HorizontalOffset;
|
||||
}
|
||||
child.Arrange(rect);
|
||||
}
|
||||
private void InvalidateScrollInfo(Size availableSize)
|
||||
{
|
||||
ItemsControl ownerItemsControl = ItemsControl.GetItemsOwner(this);
|
||||
if (ownerItemsControl != null)
|
||||
{
|
||||
Size extent = this.GetExtent(availableSize, ownerItemsControl.Items.Count);
|
||||
if (extent != this.contentExtent)
|
||||
{
|
||||
this.contentExtent = extent;
|
||||
this.RefreshOffset();
|
||||
}
|
||||
if (availableSize != this.viewport)
|
||||
{
|
||||
this.viewport = availableSize;
|
||||
this.InvalidateScrollOwner();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void RefreshOffset()
|
||||
{
|
||||
if (this.Orientation == Orientation.Horizontal)
|
||||
{
|
||||
this.SetVerticalOffset(this.VerticalOffset);
|
||||
return;
|
||||
}
|
||||
this.SetHorizontalOffset(this.HorizontalOffset);
|
||||
}
|
||||
private void InvalidateScrollOwner()
|
||||
{
|
||||
if (this.ScrollOwner != null)
|
||||
{
|
||||
this.ScrollOwner.InvalidateScrollInfo();
|
||||
}
|
||||
}
|
||||
private Size GetExtent(Size availableSize, int itemCount)
|
||||
{
|
||||
if (this.Orientation == Orientation.Horizontal)
|
||||
{
|
||||
int childrenPerRow = this.GetVerticalChildrenCountPerRow(availableSize);
|
||||
return new Size((double)childrenPerRow * this.ItemWidth, this.ItemHeight * Math.Ceiling((double)itemCount / (double)childrenPerRow));
|
||||
}
|
||||
int childrenPerRow2 = this.GetHorizontalChildrenCountPerRow(availableSize);
|
||||
return new Size(this.ItemWidth * Math.Ceiling((double)itemCount / (double)childrenPerRow2), (double)childrenPerRow2 * this.ItemHeight);
|
||||
}
|
||||
private int GetVerticalChildrenCountPerRow(Size availableSize)
|
||||
{
|
||||
int childrenCountPerRow;
|
||||
if (availableSize.Width == double.PositiveInfinity)
|
||||
{
|
||||
childrenCountPerRow = base.Children.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
childrenCountPerRow = Math.Max(1, (int)Math.Floor(availableSize.Width / this.ItemWidth));
|
||||
}
|
||||
return childrenCountPerRow;
|
||||
}
|
||||
private int GetHorizontalChildrenCountPerRow(Size availableSize)
|
||||
{
|
||||
int childrenCountPerRow;
|
||||
if (availableSize.Height == double.PositiveInfinity)
|
||||
{
|
||||
childrenCountPerRow = base.Children.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
childrenCountPerRow = Math.Max(1, (int)Math.Floor(availableSize.Height / this.ItemHeight));
|
||||
}
|
||||
return childrenCountPerRow;
|
||||
}
|
||||
|
||||
private static bool IsCloseTo(double value1, double value2)
|
||||
{
|
||||
return AreClose(value1, value2);
|
||||
}
|
||||
|
||||
private static bool AreClose(double value1, double value2)
|
||||
{
|
||||
if (value1 == value2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
double num = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * 2.2204460492503131E-16;
|
||||
double num2 = value1 - value2;
|
||||
return -num < num2 && num > num2;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user