From 865f203c1e8e730c175df7e7c86277101e12388c Mon Sep 17 00:00:00 2001 From: Abdelkarim Sellamna Date: Tue, 16 Sep 2014 22:25:47 +0100 Subject: [PATCH 1/4] Fixed DropShadow issue Fixed an issue with the DropShadowEffect in the NavigatorWindowStyle of AvalonDock. --- .../Resources/NavigatorWindowStyle.xaml | 144 +++++++++--------- 1 file changed, 76 insertions(+), 68 deletions(-) diff --git a/src/Libraries/AvalonDock/AvalonDock/Resources/NavigatorWindowStyle.xaml b/src/Libraries/AvalonDock/AvalonDock/Resources/NavigatorWindowStyle.xaml index d551c8378f..e4f7335a85 100644 --- a/src/Libraries/AvalonDock/AvalonDock/Resources/NavigatorWindowStyle.xaml +++ b/src/Libraries/AvalonDock/AvalonDock/Resources/NavigatorWindowStyle.xaml @@ -155,75 +155,83 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 5682e0062d4aa0c43381a2c187b025569717446c Mon Sep 17 00:00:00 2001 From: Abdelkarim Sellamna Date: Mon, 22 Sep 2014 08:55:27 +0100 Subject: [PATCH 2/4] Added EditorSplitContainer with an integration partially successful. --- .../AvalonEdit.AddIn/AvalonEdit.AddIn.csproj | 4 + .../AvalonEdit.AddIn/Src/CodeEditor.cs | 65 +- .../Src/EditorSplitContainer.cs | 833 ++++++++++++++++++ .../Src/EditorSplitContainerCommands.cs | 52 ++ .../AvalonEdit.AddIn/Src/SpliterGrip.cs | 58 ++ .../AvalonEdit.AddIn/themes/SpliterGrip.xaml | 28 + .../AvalonEdit.AddIn/themes/generic.xaml | 92 +- 7 files changed, 1128 insertions(+), 4 deletions(-) create mode 100644 src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainer.cs create mode 100644 src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainerCommands.cs create mode 100644 src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SpliterGrip.cs create mode 100644 src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/SpliterGrip.xaml diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj index 4fa4a0c07e..8c86cdfb8e 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj @@ -112,8 +112,11 @@ + + + @@ -217,6 +220,7 @@ SharpDevelopCompletionWindow.cs + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1} ICSharpCode.AvalonEdit diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs index 0c14792c7c..21733b07b8 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs @@ -65,6 +65,7 @@ namespace ICSharpCode.AvalonEdit.AddIn readonly TextMarkerService textMarkerService; readonly IChangeWatcher changeWatcher; ErrorPainter errorPainter; + private EditorSplitContainer _splitContainer; public CodeEditorView PrimaryTextEditor { get { return primaryTextEditor; } @@ -161,6 +162,11 @@ namespace ICSharpCode.AvalonEdit.AddIn const double minRowHeight = 40; + static CodeEditor() + { + InitEventHandlers(); + } + public CodeEditor() { CodeEditorOptions.Instance.PropertyChanged += CodeEditorOptions_Instance_PropertyChanged; @@ -187,9 +193,14 @@ namespace ICSharpCode.AvalonEdit.AddIn this.ColumnDefinitions.Add(new ColumnDefinition()); this.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto }); this.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star), MinHeight = minRowHeight }); - SetRow(primaryTextEditor, 1); - this.Children.Add(primaryTextEditor); + _splitContainer = new EditorSplitContainer + { + PrimaryView = primaryTextEditor + }; + SetRow(_splitContainer, 1); + + this.Children.Add(_splitContainer); } void CodeEditorOptions_Instance_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) @@ -250,6 +261,56 @@ namespace ICSharpCode.AvalonEdit.AddIn return codeEditorView; } + #region "EditorSplitContainer integration" + + private static void InitEventHandlers() + { + EventManager.RegisterClassHandler( + typeof (CodeEditor), + EditorSplitContainer.RequestSecondaryViewEvent, + new RequestSecondaryViewEventHandler( + (sender, args) => + { + var codeEditor = sender as CodeEditor; + if (codeEditor == null) + return; + + codeEditor.OnRequestSecondaryView(args); + })); + + EventManager.RegisterClassHandler( + typeof (CodeEditor), + EditorSplitContainer.DisposeSecondaryViewEvent, + new DisposeSecondaryViewEventHandler( + (sender, args) => + { + var codeEditor = sender as CodeEditor; + if (codeEditor == null) + return; + + codeEditor.OnDisposeOfSecondaryView(args); + })); + } + + private void OnRequestSecondaryView(RequestSecondaryViewEventArgs e) + { + e.Container = CreateTextEditor(); + e.Handled = true; + } + + private void OnDisposeOfSecondaryView(DisposeSecondaryViewEventArgs e) + { + if (e.Container == null) + return; + + // if the primary editor is being disposed of, the user chose to keep the secondary, + // swap the editors. + + e.Handled = true; + } + + #endregion + void textEditor_TextArea_TextCopied(object sender, TextEventArgs e) { ICSharpCode.SharpDevelop.Gui.TextEditorSideBar.Instance.PutInClipboardRing(e.Text); diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainer.cs new file mode 100644 index 0000000000..6b1913ea80 --- /dev/null +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainer.cs @@ -0,0 +1,833 @@ +/* + * Created by SharpDevelop. + * User: Abdelkarim + * Date: 9/22/2014 + * Time: 8:07 AM + * + */ +using System; +using System.Collections; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Threading; + +namespace ICSharpCode.AvalonEdit.AddIn +{ + [ContentProperty("PrimaryView")] + public class EditorSplitContainer : FrameworkElement + { + #region "Fields" + + private readonly Rect _emptyRect = new Rect(); + private UIElement _secondaryViewContainer; + private UIElement _primaryViewContainer; + private SpliterGrip _grip; + private readonly UIElementCollection _visualChildren; + private double _gripOffset; + // in percent + private bool _isSecondaryViewCollapsing; + private bool _isPrimaryViewCollapsing; + private bool _hideSpliterGrip; + private bool _isGripDragging; + + #endregion + + #region "Constructors" + + /// + /// Initializes static members of the class. + /// + static EditorSplitContainer() + { + ClipToBoundsProperty.OverrideMetadata(typeof(EditorSplitContainer), new FrameworkPropertyMetadata(BooleanBoxes.True)); + InitCommands(); + InitEventHandlers(); + } + + /// + /// Initializes instance members of the class. + /// + public EditorSplitContainer() + { + InitSplitterHandle(); + _visualChildren = new UIElementCollection(this, this) { _grip }; + LoadInInitialLayout(); + } + + #endregion + + #region "Events" + + #region RequestSecondaryView + + /// + /// RequestSecondaryView Routed Event + /// + public static readonly RoutedEvent RequestSecondaryViewEvent = EventManager.RegisterRoutedEvent("RequestSecondaryView", + RoutingStrategy.Bubble, typeof(RequestSecondaryViewEventHandler), typeof(EditorSplitContainer)); + + /// + /// Occurs when ... + /// + public event RequestSecondaryViewEventHandler RequestSecondaryView { + add { AddHandler(RequestSecondaryViewEvent, value); } + remove { RemoveHandler(RequestSecondaryViewEvent, value); } + } + + /// + /// + /// + /// + protected RequestSecondaryViewEventArgs RaiseRequestSecondaryViewEvent() + { + var args = new RequestSecondaryViewEventArgs { RoutedEvent = RequestSecondaryViewEvent }; + this.RaiseEvent(args); + return args; + } + + #endregion + + #region DisposeSecondaryView + + /// + /// DisposeSecondaryView Routed Event + /// + public static readonly RoutedEvent DisposeSecondaryViewEvent = EventManager.RegisterRoutedEvent( + "DisposeSecondaryView", + RoutingStrategy.Bubble, + typeof(DisposeSecondaryViewEventHandler), + typeof(EditorSplitContainer)); + + /// + /// Occurs when ... + /// + public event DisposeSecondaryViewEventHandler DisposeSecondaryView { + add { AddHandler(DisposeSecondaryViewEvent, value); } + remove { RemoveHandler(DisposeSecondaryViewEvent, value); } + } + + /// + /// A helper method to raise the event. + /// + protected void RaiseDisposeSecondaryViewEvent(object container) + { + // It is not immediately raised, but when idle. + // In case the dispose operation is expensive. + + this.Dispatcher.BeginInvoke( + DispatcherPriority.ApplicationIdle, + new Action(c => { + var args = new DisposeSecondaryViewEventArgs { + RoutedEvent = DisposeSecondaryViewEvent, + Container = c + }; + this.RaiseEvent(args); + }), + container); + } + + #endregion + + #endregion + + #region "Static Methods" + + private static void InitCommands() + { + CommandManager.RegisterClassCommandBinding(typeof(EditorSplitContainer), new CommandBinding( + EditorSplitContainerCommands.SplitEditorCommand, + (sender, e) => { + var container = sender as EditorSplitContainer; + if (container == null) + return; + container.OnSplitEditor(); + }, + (sender, e) => { + var container = sender as EditorSplitContainer; + if (container == null) + return; + + e.CanExecute = container.IsSplit; + })); + + CommandManager.RegisterClassCommandBinding(typeof(EditorSplitContainer), new CommandBinding( + EditorSplitContainerCommands.RemoveSplitCommand, + (sender, e) => { + var container = sender as EditorSplitContainer; + if (container == null) + return; + container.OnRemoveSplit(); + }, + (sender, e) => { + var container = sender as EditorSplitContainer; + if (container == null) + return; + + e.CanExecute = !container.IsSplit; + })); + } + + private static void InitEventHandlers() + { + EventManager.RegisterClassHandler(typeof(EditorSplitContainer), Thumb.DragStartedEvent, new DragStartedEventHandler(OnEditorGripDragStarted)); + EventManager.RegisterClassHandler(typeof(EditorSplitContainer), Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnEditorGripDragDelta)); + EventManager.RegisterClassHandler(typeof(EditorSplitContainer), Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnEditorGripDragCompleted)); + } + + private static void OnEditorGripDragCompleted(object sender, DragCompletedEventArgs e) + { + var splitContainer = sender as EditorSplitContainer; + if (splitContainer == null) + return; + + var thumb = e.OriginalSource as Thumb; + if (thumb == null || thumb == splitContainer._grip || thumb.Name != "PART_EditorGrip") + return; + + splitContainer.OnDragCompleted(); + } + + private static void OnEditorGripDragDelta(object sender, DragDeltaEventArgs e) + { + var splitContainer = sender as EditorSplitContainer; + if (splitContainer == null) + return; + + var thumb = e.OriginalSource as Thumb; + if (thumb == null || thumb == splitContainer._grip || thumb.Name != "PART_EditorGrip") + return; + + splitContainer.OnEditorGripDragDelta(splitContainer.Orientation == Orientation.Horizontal + ? e.VerticalChange + : e.HorizontalChange); + + e.Handled = true; + } + + private static void OnEditorGripDragStarted(object sender, DragStartedEventArgs e) + { + var splitContainer = sender as EditorSplitContainer; + if (splitContainer == null) + return; + + var thumb = e.OriginalSource as Thumb; + if (thumb == null || thumb == splitContainer._grip || thumb.Name != "PART_EditorGrip") + return; + + // when this occur the editor grip is visible, and the split container has only + // one view in it, the 2nd view. + splitContainer.OnDragStarted(); + } + + #endregion + + #region "Properties" + + #region Orientation + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register( + "Orientation", + typeof(Orientation), + typeof(EditorSplitContainer), + new FrameworkPropertyMetadata(Orientation.Horizontal, + FrameworkPropertyMetadataOptions.AffectsArrange, + (o, e) => { + var splitContainer = o as EditorSplitContainer; + if (splitContainer == null || splitContainer._grip == null) + return; + + splitContainer._grip.Orientation = (Orientation)e.NewValue; + }), + IsValidOrientation); + + private static bool IsValidOrientation(object value) + { + var orientation = (Orientation)value; + return orientation == Orientation.Horizontal || orientation == Orientation.Vertical; + } + + /// + /// Gets or sets the Orientation property. This is a dependency property. + /// + /// + /// + /// + [Bindable(true)] + public Orientation Orientation { + get { return (Orientation)GetValue(OrientationProperty); } + set { SetValue(OrientationProperty, value); } + } + + #endregion + + #region IsSplit + + private static readonly DependencyPropertyKey IsSplitPropertyKey = DependencyProperty.RegisterReadOnly( + "IsSplit", + typeof(bool), + typeof(EditorSplitContainer), + new FrameworkPropertyMetadata( + BooleanBoxes.False, + (o, args) => { + var container = (EditorSplitContainer)o; + container.OnIsSplitChanged((bool)args.NewValue); + })); + + public static readonly DependencyProperty IsSplitProperty = IsSplitPropertyKey.DependencyProperty; + + /// + /// Gets a value that indicates whether the editor is split into two. + /// + public bool IsSplit { + get { return (bool)GetValue(IsSplitProperty); } + internal set { SetValue(IsSplitPropertyKey, value); } + } + + #endregion + + #endregion + + #region "Plain Properties" + + /// + /// Gets the number of visual child elements within this element. + /// + /// + /// The number of visual child elements for this element. + /// + protected override int VisualChildrenCount { + get { + if (_visualChildren == null) + return 0; + + return _visualChildren.Count; + } + } + + /// + /// Gets an enumerator for logical child elements of this element. + /// + /// + /// An enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren { + get { + var arrayList = new ArrayList(3); + + foreach (var child in _visualChildren) + arrayList.Add(child); + + return arrayList.GetEnumerator(); + } + } + + /// + /// The element that hosts the secondary view. + /// + public UIElement SecondaryView { + get { return _secondaryViewContainer == null ? null : _secondaryViewContainer; } + private set { + UpdateView(_secondaryViewContainer, value); + _secondaryViewContainer = value; + } + } + + /// + /// The element that hosts the primary view. + /// + public UIElement PrimaryView { + get { return _primaryViewContainer; } + set { + if (_primaryViewContainer == value) + throw new NotSupportedException(""); + + UpdateView(_primaryViewContainer, value); + _primaryViewContainer = value; + } + } + + /// + /// Gets a value that indicates whether we can snap the spliter grip to the top edge. + /// + private bool CanCollapseSecondaryView { + get { + if (Density > 0) { + var offset = 20 * Density; + return _gripOffset <= offset; + } + + return false; + } + } + + /// + /// Gets a value that indicates whether we can snap the spliter grip to the bottom edge + /// + private bool CanCollapsePrimaryView { + get { + if (Density > 0) { + var offset = 20 * Density; + return _gripOffset >= (100 - offset); + } + return false; + } + } + + private double Density { get; set; } + private bool InternalIsSplit { get; set; } + + #endregion + + #region "Public Methods" + + /// + /// Will split the editor into half. + /// + public void OnSplitEditor() + { + if (!IsSplit) + return; + + _gripOffset = 50; + ComputeOffset(0); + + InternalIsSplit = false; + IsSplit = false; + + InvalidateVisual(); + } + + /// + /// Will remove the split from the editor if it is present + /// + public void OnRemoveSplit() + { + if (IsSplit) + return; + + _gripOffset = 0; + ComputeOffset(0); + + InternalIsSplit = true; + IsSplit = true; + + InvalidateVisual(); + } + + #endregion + + #region "Protected Overrides" + + protected override Visual GetVisualChild(int index) + { + if (_visualChildren == null || (index < 0 || index >= _visualChildren.Count)) + throw new ArgumentOutOfRangeException("index"); + + return _visualChildren[index]; + } + + protected override Size MeasureOverride(Size availableSize) + { + bool isHorizontal = Orientation == Orientation.Horizontal; + + if (isHorizontal && (double.IsPositiveInfinity(availableSize.Height) || double.IsInfinity(availableSize.Height))) + return base.MeasureOverride(availableSize); + + if (!isHorizontal && (double.IsPositiveInfinity(availableSize.Width) || double.IsInfinity(availableSize.Width))) + return base.MeasureOverride(availableSize); + + double startPos, handleSize, secondaryViewSize, primaryViewSize; + this.ComputePartsSizes(availableSize, isHorizontal, out secondaryViewSize, out primaryViewSize, out handleSize, out startPos); + + var secondaryView = SecondaryView; + if (secondaryView != null) + secondaryView.Measure(isHorizontal + ? new Size(availableSize.Width, secondaryViewSize) + : new Size(secondaryViewSize, availableSize.Height)); + + var view2 = PrimaryView; + if (view2 != null) + view2.Measure(isHorizontal + ? new Size(availableSize.Width, primaryViewSize) + : new Size(primaryViewSize, availableSize.Height)); + + _grip.Measure(availableSize); + return _grip.DesiredSize; + } + + protected override Size ArrangeOverride(Size finalSize) + { + // initialization + var isHorizontal = Orientation == Orientation.Horizontal; + var secondaryView = SecondaryView; + var primaryView = PrimaryView; + + double secondaryViewSize, primaryViewSize, gripSize, startPos; + ComputePartsSizes(finalSize, isHorizontal, out secondaryViewSize, out primaryViewSize, out gripSize, out startPos); + + + Rect finalRect = isHorizontal + ? new Rect { + Location = new Point(0, startPos), + Width = finalSize.Width + } + : new Rect { + Location = new Point(startPos, 0), + Height = finalSize.Height + }; + + if (InternalIsSplit) { + if (_isSecondaryViewCollapsing) { + // SecondaryView + if (secondaryView != null) + secondaryView.Arrange(_emptyRect); + + // Grip + if (isHorizontal) { + finalRect.Y = startPos; + finalRect.Height = gripSize; + } else { + finalRect.X = startPos; + finalRect.Width = gripSize; + } + _grip.Arrange(!_hideSpliterGrip ? finalRect : _emptyRect); + + // view2 + if (isHorizontal) { + finalRect.Y += gripSize; + finalRect.Height = primaryViewSize; + } else { + finalRect.X += gripSize; + finalRect.Width = primaryViewSize; + } + + if (primaryView != null) + primaryView.Arrange(finalRect); + } + + if (_isPrimaryViewCollapsing) { + // SecondaryView + if (isHorizontal) + finalRect.Height = secondaryViewSize; + else + finalRect.Width = secondaryViewSize; + if (secondaryView != null) + secondaryView.Arrange(finalRect); + + // Grip + if (isHorizontal) { + finalRect.Y += secondaryViewSize; + finalRect.Height = gripSize; + } else { + finalRect.X += secondaryViewSize; + finalRect.Width = gripSize; + } + _grip.Arrange(!_hideSpliterGrip ? finalRect : _emptyRect); + + // PrimaryView + if (primaryView != null) + primaryView.Arrange(_emptyRect); + } + } else { + // SecondaryView + if (isHorizontal) + finalRect.Height = secondaryViewSize; + else + finalRect.Width = secondaryViewSize; + + + if (secondaryView != null) + secondaryView.Arrange(finalRect); + + // grip + if (isHorizontal) { + finalRect.Y += secondaryViewSize; + finalRect.Height = gripSize; + } else { + finalRect.X += secondaryViewSize; + finalRect.Width = gripSize; + } + _grip.Arrange(finalRect); + + // PrimaryView + if (isHorizontal) { + finalRect.Y += gripSize; + finalRect.Height = primaryViewSize; + } else { + finalRect.X += gripSize; + finalRect.Width = primaryViewSize; + } + + if (primaryView != null) + primaryView.Arrange(finalRect); + } + + return finalSize; + } + + #endregion + + #region "Methods" + + private void InitSplitterHandle() + { + _grip = new SpliterGrip { + Orientation = this.Orientation + }; + + _grip.DragStarted += OnDragStarted; + _grip.DragDelta += OnGripDragDelta; + _grip.DragCompleted += OnDragCompleted; + } + + private void OnIsSplitChanged(bool newValue) + { + if (!newValue) { + var args = RaiseRequestSecondaryViewEvent(); + var container = args.Container as UIElement; + if (container == null) + return; + + SecondaryView = container; + } else { + var secondaryView = this.SecondaryView; + if (secondaryView == null) + return; + + SecondaryView = null; // will cause it to be removed from the logical/visual trees. + + RaiseDisposeSecondaryViewEvent(secondaryView); + } + } + + private void OnDragStarted(object sender, DragStartedEventArgs e) + { + OnDragStarted(); + } + + private void OnDragStarted() + { + _hideSpliterGrip = false; + _isGripDragging = true; + IsSplit = false; + } + + private void LoadInInitialLayout() + { + ComputeOffset(0); + IsSplit = InternalIsSplit; + } + + private void OnDragCompleted(object sender, DragCompletedEventArgs e) + { + OnDragCompleted(); + } + + /// + /// Common method between split container grip, and editor grip + /// + private void OnDragCompleted() + { + _isGripDragging = false; + + if (!_isSecondaryViewCollapsing && !_isPrimaryViewCollapsing) { + // we need to check if we are close to be collapsed, we snap one of them. + if (CanCollapseSecondaryView) { + _isSecondaryViewCollapsing = true; + InternalIsSplit = true; + } else if (CanCollapsePrimaryView) { + _isPrimaryViewCollapsing = true; + InternalIsSplit = true; + } else { + IsSplit = false; + return; + } + } + + _hideSpliterGrip = InternalIsSplit; + + // a final layout pass is to be made, in order to ensure + // that the active view has been measure/arrange against the available + // space. + + if (InternalIsSplit) { + if (_isPrimaryViewCollapsing) + SwapViews(); + + // reset the offset + _gripOffset = -(6 * Density); + _isSecondaryViewCollapsing = true; + _isPrimaryViewCollapsing = false; + + InvalidateMeasure(); + InvalidateArrange(); + } + + IsSplit = InternalIsSplit; + } + + private void OnGripDragDelta(object sender, DragDeltaEventArgs e) { + bool isHorizontal = Orientation == Orientation.Horizontal; + double change = isHorizontal ? e.VerticalChange : e.HorizontalChange; + + ComputeOffset(change); + e.Handled = true; + } + + protected void OnEditorGripDragDelta(double change) { + ComputeOffset(change); + } + + private void ComputeOffset(double change) { + //double offset = double.IsNaN(_gripOffset) ? 50 : _gripOffset; + double offset = _gripOffset; + offset += Density * change; + + CoerceOffset(ref offset); + + _gripOffset = offset; + InvalidateMeasure(); + InvalidateArrange(); + } + + private void CoerceOffset(ref double offset) + { + _isPrimaryViewCollapsing = _isSecondaryViewCollapsing = false; + bool isCollapsed = false; + double min = 0; + double max = 100; + + var gripOffset = Density * 6; + + min -= gripOffset; + max += gripOffset; + + + if (offset < min) { + offset = min; + } else if (offset > max) { + offset = max; + } + + if (offset <= 0) { + isCollapsed = true; + _isSecondaryViewCollapsing = true; + _isPrimaryViewCollapsing = false; + } else if (offset >= 100) { + isCollapsed = true; + _isSecondaryViewCollapsing = false; + _isPrimaryViewCollapsing = true; + } + + InternalIsSplit = isCollapsed; + } + + private void UpdateView(UIElement oldView, UIElement newView) + { + if (oldView == newView) + return; + + if (oldView != null) + _visualChildren.Remove(oldView); + + if (newView != null) + _visualChildren.Add(newView); + + InvalidateMeasure(); + InvalidateArrange(); + } + + private void ComputePartsSizes(Size arrangeSize, + bool isHorizontal, + out double secondaryViewSize, + out double primaryViewSize, + out double handleSize, + out double startPos) + { + double offset = double.IsNaN(_gripOffset) ? 50 : _gripOffset; + startPos = 0; + + // ensure proper sizes are selected. + double length; + if (isHorizontal) { + length = arrangeSize.Height; + handleSize = _grip.DesiredSize.Height; + } else { + length = arrangeSize.Width; + handleSize = _grip.DesiredSize.Width; + } + + // compute density; + + + + double remainingLength; + if (InternalIsSplit && !_isGripDragging) { + // only a single view is rendered, PrimaryView + remainingLength = length; + secondaryViewSize = 0; + primaryViewSize = remainingLength; + startPos = -handleSize; + + // ensure that grip offset is correctly set. + var density = 100 / remainingLength; + _gripOffset = -(density * handleSize); + } else { + remainingLength = length - handleSize; + if (offset >= 0 && offset <= 100) { + secondaryViewSize = remainingLength * (offset / 100); + primaryViewSize = remainingLength - secondaryViewSize; + } else if (offset < 0) { + double handleVisiblePart = Math.Max(0.0, handleSize - (Math.Abs(offset) / 100) * remainingLength); + startPos = (handleSize - handleVisiblePart) * -1; + secondaryViewSize = primaryViewSize = length - handleVisiblePart; + } else { //offset > 100 + double handleVisiblePart = Math.Max(0.0, handleSize - ((offset - 100) / 100) * remainingLength); + primaryViewSize = secondaryViewSize = length - handleVisiblePart; + } + } + + Density = 100 / remainingLength; + } + + private void SwapViews() + { + var temp = _secondaryViewContainer; + _secondaryViewContainer = _primaryViewContainer; + _primaryViewContainer = temp; + } + + #endregion + } + + public class RequestSecondaryViewEventArgs : RoutedEventArgs + { + public object Container { get; set; } + } + public delegate void RequestSecondaryViewEventHandler(object sender, RequestSecondaryViewEventArgs e); + + public class DisposeSecondaryViewEventArgs : RoutedEventArgs + { + public object Container { get; set; } + } + public delegate void DisposeSecondaryViewEventHandler(object sender, DisposeSecondaryViewEventArgs e); + + internal static class BooleanBoxes + { + public static object True = true; + public static object False = false; + + public static object Box(bool value) + { + return value ? True : False; + } + } +} diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainerCommands.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainerCommands.cs new file mode 100644 index 0000000000..4d096d174a --- /dev/null +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/EditorSplitContainerCommands.cs @@ -0,0 +1,52 @@ +/* + * Created by SharpDevelop. + * User: Abdelkarim + * Date: 9/22/2014 + * Time: 8:07 AM + * + */ +using System; +using System.Collections; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Threading; + +namespace ICSharpCode.AvalonEdit.AddIn +{ + public static class EditorSplitContainerCommands + { + private static RoutedUICommand _splitEditorCommand; + + private static RoutedUICommand _removeSplitCommand; + + /// + /// + /// + public static RoutedUICommand SplitEditorCommand { + get { + if (_splitEditorCommand == null) + _splitEditorCommand = new RoutedUICommand("Split", "SplitEditor", typeof(EditorSplitContainerCommands)); + return _splitEditorCommand; + } + } + + /// + /// + /// + public static RoutedUICommand RemoveSplitCommand { + get { + if (_removeSplitCommand == null) { + _removeSplitCommand = new RoutedUICommand("Remove Split", "RemoveSplitEditor", typeof(EditorSplitContainerCommands)); + } + return _removeSplitCommand; + } + } + } +} + + diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SpliterGrip.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SpliterGrip.cs new file mode 100644 index 0000000000..0abf6cd1ea --- /dev/null +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/SpliterGrip.cs @@ -0,0 +1,58 @@ +/* + * Created by SharpDevelop. + * User: Abdelkarim + * Date: 9/22/2014 + * Time: 8:07 AM + * + */ +using System; +using System.Collections; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Threading; +namespace ICSharpCode.AvalonEdit.AddIn +{ + public class SpliterGrip : Thumb + { + #region "Constructors" + /// + /// initializes static members of the class. + /// + static SpliterGrip() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SpliterGrip), new FrameworkPropertyMetadata(typeof(SpliterGrip))); + } + + #endregion + #region "Properties" + #region Orientation + /// + /// Orientation Read-Only Dependency Property + /// + private static readonly DependencyPropertyKey OrientationPropertyKey = DependencyProperty.RegisterReadOnly("Orientation", typeof(Orientation), typeof(SpliterGrip), new FrameworkPropertyMetadata(Orientation.Horizontal)); + + public static readonly DependencyProperty OrientationProperty = OrientationPropertyKey.DependencyProperty; + + /// + /// Gets the Orientation property. This dependency property + /// indicates .... + /// + public Orientation Orientation { + get { + return (Orientation)GetValue(OrientationProperty); + } + internal set { + SetValue(OrientationPropertyKey, value); + } + } + #endregion + #endregion + } +} + + diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/SpliterGrip.xaml b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/SpliterGrip.xaml new file mode 100644 index 0000000000..5bd202bac3 --- /dev/null +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/SpliterGrip.xaml @@ -0,0 +1,28 @@ + + + + + \ No newline at end of file diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/generic.xaml b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/generic.xaml index d16f35dace..3d93496b1f 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/generic.xaml +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/themes/generic.xaml @@ -3,8 +3,95 @@ xmlns:ae="http://icsharpcode.net/sharpdevelop/avalonedit" xmlns:local="clr-namespace:ICSharpCode.AvalonEdit.AddIn" xmlns:widgets="http://icsharpcode.net/sharpdevelop/widgets" - xmlns:core="http://icsharpcode.net/sharpdevelop/core" -> + xmlns:core="http://icsharpcode.net/sharpdevelop/core"> + + + + + + + M 0,5 L0,6 L11,6 L11,5 L6,5 L6,3 L8,3 L8,2 L7,2 L7,1 L6,1 L6,0 L5,0 L5,1 L4,1 L4,2 L3,2 L3,3 L5,3 L5,5 Z + M 0,8 L0,7 L11,7 L11,8 L6,8 L6,10 L8,10 L8,11 L7,11 L7,12 L6,12 L6,13 L5,13 L5,12 L4,12 L4,11 L3,11 L3,10 L5,10 L5,8 Z + + + + + +