You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
8.9 KiB
272 lines
8.9 KiB
/*************************************************************************************
|
|
|
|
Extended WPF Toolkit
|
|
|
|
Copyright (C) 2007-2013 Xceed Software Inc.
|
|
|
|
This program is provided to you under the terms of the Microsoft Public
|
|
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
|
|
|
For more features, controls, and fast professional support,
|
|
pick up the Plus Edition at http://xceed.com/wpf_toolkit
|
|
|
|
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
|
|
|
***********************************************************************************/
|
|
|
|
using System;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using Xceed.Wpf.Toolkit.Core;
|
|
using Xceed.Wpf.Toolkit.Core.Utilities;
|
|
|
|
namespace Xceed.Wpf.Toolkit
|
|
{
|
|
public class RichTextBoxFormatBarManager : DependencyObject
|
|
{
|
|
#region Members
|
|
|
|
private global::System.Windows.Controls.RichTextBox _richTextBox;
|
|
private UIElementAdorner<Control> _adorner;
|
|
private IRichTextBoxFormatBar _toolbar;
|
|
private Window _parentWindow;
|
|
|
|
private const double _hideAdornerDistance = 150d;
|
|
|
|
#endregion //Members
|
|
|
|
#region Properties
|
|
|
|
#region FormatBar
|
|
|
|
public static readonly DependencyProperty FormatBarProperty = DependencyProperty.RegisterAttached( "FormatBar", typeof( IRichTextBoxFormatBar ), typeof( RichTextBox ), new PropertyMetadata( null, OnFormatBarPropertyChanged ) );
|
|
public static void SetFormatBar( UIElement element, IRichTextBoxFormatBar value )
|
|
{
|
|
element.SetValue( FormatBarProperty, value );
|
|
}
|
|
public static IRichTextBoxFormatBar GetFormatBar( UIElement element )
|
|
{
|
|
return ( IRichTextBoxFormatBar )element.GetValue( FormatBarProperty );
|
|
}
|
|
|
|
private static void OnFormatBarPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
|
|
{
|
|
global::System.Windows.Controls.RichTextBox rtb = d as global::System.Windows.Controls.RichTextBox;
|
|
if( rtb == null )
|
|
throw new Exception( "A FormatBar can only be applied to a RichTextBox." );
|
|
|
|
RichTextBoxFormatBarManager manager = new RichTextBoxFormatBarManager();
|
|
manager.AttachFormatBarToRichtextBox( rtb, e.NewValue as IRichTextBoxFormatBar );
|
|
}
|
|
|
|
#endregion //FormatBar
|
|
|
|
public bool IsAdornerVisible
|
|
{
|
|
get
|
|
{
|
|
return _adorner.Visibility == Visibility.Visible;
|
|
}
|
|
}
|
|
|
|
#endregion //Properties
|
|
|
|
#region Event Handlers
|
|
|
|
void RichTextBox_MouseButtonUp( object sender, MouseButtonEventArgs e )
|
|
{
|
|
if( e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Released )
|
|
{
|
|
if( !_richTextBox.IsReadOnly )
|
|
{
|
|
TextRange selectedText = new TextRange( _richTextBox.Selection.Start, _richTextBox.Selection.End );
|
|
#if !VS2008
|
|
if( selectedText.Text.Length > 0 && !String.IsNullOrWhiteSpace( selectedText.Text ) )
|
|
ShowAdorner();
|
|
#else
|
|
if( selectedText.Text.Length > 0 && !String.IsNullOrEmpty( selectedText.Text ) )
|
|
ShowAdorner();
|
|
#endif
|
|
else
|
|
HideAdorner();
|
|
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
else
|
|
HideAdorner();
|
|
}
|
|
|
|
private void OnPreviewMouseMoveParentWindow( object sender, MouseEventArgs e )
|
|
{
|
|
Point p = e.GetPosition( _adorner );
|
|
double maxDist = 0d;
|
|
bool preventDisplayFadeOut = ( ( _adorner.Child != null ) && ( _adorner.Child is IRichTextBoxFormatBar ) ) ?
|
|
( ( IRichTextBoxFormatBar )_adorner.Child ).PreventDisplayFadeOut :
|
|
false;
|
|
|
|
//Mouse is inside FormatBar: Nothing to do.
|
|
if( preventDisplayFadeOut ||
|
|
( p.X >= 0 ) && ( p.X <= _adorner.ActualWidth ) && ( p.Y >= 0 ) && ( p.Y <= _adorner.ActualHeight ) )
|
|
{
|
|
return;
|
|
}
|
|
//Mouse is too much outside FormatBar: Close it.
|
|
else if( ( p.X < -_hideAdornerDistance ) || ( p.X > _adorner.ActualWidth + _hideAdornerDistance ) || ( p.Y < -_hideAdornerDistance ) || ( p.Y > _adorner.ActualHeight + _hideAdornerDistance ) )
|
|
{
|
|
HideAdorner();
|
|
}
|
|
//Mouse is just outside FormatBar: Vary its opacity.
|
|
else
|
|
{
|
|
if( p.X < 0 )
|
|
maxDist = -p.X;
|
|
else if( p.X > _adorner.ActualWidth )
|
|
maxDist = p.X - _adorner.ActualWidth;
|
|
|
|
if( p.Y < 0 )
|
|
maxDist = Math.Max( maxDist, -p.Y );
|
|
else if( p.Y > _adorner.ActualHeight )
|
|
maxDist = Math.Max( maxDist, p.Y - _adorner.ActualHeight );
|
|
|
|
_adorner.Opacity = 1d - ( Math.Min( maxDist, 100d ) / 100d );
|
|
}
|
|
}
|
|
|
|
void RichTextBox_TextChanged( object sender, TextChangedEventArgs e )
|
|
{
|
|
//This fixes the bug when applying text transformations the text would lose it's highlight. That was because the RichTextBox was losing focus,
|
|
//so we just give it focus again and it seems to do the trick of re-highlighting it.
|
|
if( !_richTextBox.IsFocused && !_richTextBox.Selection.IsEmpty )
|
|
_richTextBox.Focus();
|
|
}
|
|
|
|
#endregion //Event Handlers
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// Attaches a FormatBar to a RichtextBox
|
|
/// </summary>
|
|
/// <param name="richTextBox">The RichtextBox to attach to.</param>
|
|
/// <param name="formatBar">The Formatbar to attach.</param>
|
|
private void AttachFormatBarToRichtextBox( global::System.Windows.Controls.RichTextBox richTextBox, IRichTextBoxFormatBar formatBar )
|
|
{
|
|
_richTextBox = richTextBox;
|
|
//we cannot use the PreviewMouseLeftButtonUp event because of selection bugs.
|
|
//we cannot use the MouseLeftButtonUp event because it is handled by the RichTextBox and does not bubble up to here, so we must
|
|
//add a hander to the MouseUpEvent using the Addhandler syntax, and specify to listen for handled events too.
|
|
_richTextBox.AddHandler( Mouse.MouseUpEvent, new MouseButtonEventHandler( RichTextBox_MouseButtonUp ), true );
|
|
_richTextBox.TextChanged += RichTextBox_TextChanged;
|
|
|
|
_adorner = new UIElementAdorner<Control>( _richTextBox );
|
|
|
|
formatBar.Target = _richTextBox;
|
|
_toolbar = formatBar;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows the FormatBar
|
|
/// </summary>
|
|
void ShowAdorner()
|
|
{
|
|
if( _adorner.Visibility == Visibility.Visible )
|
|
return;
|
|
|
|
VerifyAdornerLayer();
|
|
|
|
Control adorningEditor = _toolbar as Control;
|
|
|
|
if( _adorner.Child == null )
|
|
_adorner.Child = adorningEditor;
|
|
|
|
adorningEditor.ApplyTemplate();
|
|
_toolbar.Update();
|
|
|
|
_adorner.Visibility = Visibility.Visible;
|
|
|
|
PositionFormatBar( adorningEditor );
|
|
|
|
_parentWindow = TreeHelper.FindParent<Window>( _adorner );
|
|
if( _parentWindow != null )
|
|
{
|
|
Mouse.AddMouseMoveHandler( _parentWindow, OnPreviewMouseMoveParentWindow );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Positions the FormatBar so that is does not go outside the bounds of the RichTextBox or covers the selected text
|
|
/// </summary>
|
|
/// <param name="adorningEditor"></param>
|
|
private void PositionFormatBar( Control adorningEditor )
|
|
{
|
|
Point mousePosition = Mouse.GetPosition( _richTextBox );
|
|
|
|
double left = mousePosition.X;
|
|
double top = ( mousePosition.Y - 15 ) - adorningEditor.ActualHeight;
|
|
|
|
//top
|
|
if( top < 0 )
|
|
{
|
|
top = Math.Max( mousePosition.Y + 10, 5 );
|
|
}
|
|
|
|
// bottom
|
|
if ( top + adorningEditor.ActualHeight > _richTextBox.ActualHeight - 20 )
|
|
{
|
|
top = _richTextBox.ActualHeight - adorningEditor.ActualHeight - 20;
|
|
}
|
|
|
|
// left boundary
|
|
if ( left < 0 )
|
|
{
|
|
left = 5;
|
|
}
|
|
|
|
//right boundary
|
|
if( left + adorningEditor.ActualWidth > _richTextBox.ActualWidth - 20 )
|
|
{
|
|
left = _richTextBox.ActualWidth - adorningEditor.ActualWidth - 20;
|
|
}
|
|
|
|
_adorner.SetOffsets( left, top );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures that the IRichTextFormatBar is in the adorner layer.
|
|
/// </summary>
|
|
/// <returns>True if the IRichTextFormatBar is in the adorner layer, else false.</returns>
|
|
bool VerifyAdornerLayer()
|
|
{
|
|
if( _adorner.Parent != null )
|
|
return true;
|
|
|
|
AdornerLayer layer = AdornerLayer.GetAdornerLayer( _richTextBox );
|
|
if( layer == null )
|
|
return false;
|
|
|
|
layer.Add( _adorner );
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hides the IRichTextFormatBar that is in the adornor layer.
|
|
/// </summary>
|
|
void HideAdorner()
|
|
{
|
|
if( IsAdornerVisible )
|
|
{
|
|
_adorner.Visibility = Visibility.Collapsed;
|
|
//_adorner.Child = null;
|
|
if( _parentWindow != null )
|
|
{
|
|
Mouse.RemoveMouseMoveHandler( _parentWindow, OnPreviewMouseMoveParentWindow );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion //Methods
|
|
}
|
|
}
|
|
|