/// <summary> /// Resets all fields. /// </summary> private void Reset() { Debug.Assert(Mouse.Captured == null); Debug.Assert(_borderDockIndicators == null); Debug.Assert(_paneDockIndicators == null); Debug.Assert( _dockStrategy == null || !_dockStrategy.DockControl.GetDockElements().OfType <DockTabItemProxy>().Any(), "All item proxies should have been removed."); _dockStrategy = null; _draggedItems.Clear(); _activeItem = null; _floatWindow = null; _targetDockTabPane = null; _layoutChanged = false; _initialMousePosition = new Point(double.NaN, double.NaN); _dragDeltaExceeded = false; _mouseOffset = new Vector(double.NaN, double.NaN); _initialSize = new Size(double.NaN, double.NaN); _canFloat = true; _originalDockState = DockState.Hide; _originalFloatWindow = null; _originalFloatLeft = 0; _originalFloatTop = 0; }
private void UpdateDockPaneContent() { if (IsSelected) { // DockTabItem is visible: Show new content in parent DockTabPane. DockTabPane?.UpdateSelectedContent(); } }
/// <summary> /// Registers the specified <see cref="DockTabPane"/>. /// </summary> /// <param name="dockTabPane">The <see cref="DockTabPane"/> to add.</param> internal void Register(DockTabPane dockTabPane) { Debug.Assert(dockTabPane != null); if (!_dockTabPanes.Contains(dockTabPane)) { _dockTabPanes.Add(dockTabPane); } }
protected internal virtual void OnDeactivated(RoutedEventArgs eventArgs) { Debug.Assert(IsActive, "DockTabItem.OnDeactivated should only be called when item is active."); IsActive = false; // Raise Deactivated event. Debug.Assert(eventArgs.RoutedEvent == DeactivatedEvent, "Invalid arguments for DockTabItem.OnDeactivated."); RaiseEvent(eventArgs); // Update visual states. UpdateVisualStates(true); DockTabPane?.UpdateVisualStates(true); }
/// <summary> /// Gets the <see cref="DockTabItem"/> at the mouse position by testing against the /// <see cref="DockTabItem"/> tabs in the specified pane. /// </summary> /// <param name="dockTabPane">The <see cref="DockTabPane"/>.</param> /// <param name="verticalTolerance"> /// The tolerance (margin at top and bottom) in pixels. /// </param> /// <returns>The <see cref="DockTabItem"/> under the mouse cursor.</returns> private static DockTabItem GetDockTabItemAtMouse(DockTabPane dockTabPane, double verticalTolerance = 0) { Debug.Assert(dockTabPane != null); if (dockTabPane.Items.Count == 0) { return(null); // Empty DockTabPane. } var itemsPanel = dockTabPane.GetItemsPanel(); if (itemsPanel == null) { return(null); // ItemsPanel missing. } Point mousePosition = WindowsHelper.GetMousePosition(itemsPanel); Rect bounds = new Rect(itemsPanel.RenderSize); bounds.Inflate(0, verticalTolerance); if (!bounds.Contains(mousePosition)) { return(null); // Mouse position outside ItemsPanel. } // Test mouse position against DockTabItems bounds. double height = itemsPanel.RenderSize.Height; double x = 0; for (int i = 0; i < dockTabPane.Items.Count; i++) { var dockTabItem = dockTabPane.ItemContainerGenerator.ContainerFromIndex(i) as DockTabItem; if (dockTabItem == null) { break; } bounds = new Rect(new Point(x, 0), new Size(dockTabItem.RenderSize.Width, height)); bounds.Inflate(0, verticalTolerance); if (bounds.Contains(mousePosition)) { return(dockTabItem); } x += bounds.Width; } return(null); }
protected internal virtual void OnActivated(RoutedEventArgs eventArgs) { Debug.Assert(!IsActive, "DockTabItem.OnActivated should not be called when item is active."); // Set DockControl.ActiveDockTabPane/ActiveDockTabItem. SetActiveItem(); IsActive = true; // Deactivate other DockTabItems and raise Deactivated event. DeactivateOtherItems(); // Raise Activated event. Debug.Assert(eventArgs.RoutedEvent == ActivatedEvent, "Invalid arguments for DockTabItem.OnActivated."); RaiseEvent(eventArgs); // Update visual states. UpdateVisualStates(true); DockTabPane?.UpdateVisualStates(true); }
/// <summary> /// Tries to move the dragged items from the <see cref="FloatWindow"/> into a /// <see cref="DockTabPanel"/>. /// </summary> private void DragFloatWindowIntoDockTabPanel() { Debug.Assert(_targetDockTabPane == null); Debug.Assert(_floatWindow != null); var dockTabPane = GetTargetPane() as DockTabPane; if (dockTabPane == null) { return; // No DockTabPane (view). } var dockTabPaneVM = dockTabPane.GetViewModel(); if (dockTabPaneVM == null) { return; // No IDockTabPane (view-model). } if (GetDockTabItemAtMouse(dockTabPane) == null) { return; // No DockTabItem hit. } if (!CanDock(dockTabPaneVM, DockPosition.Inside)) { return; // Docking not allowed. } // Remove currently dragged FloatWindow. var floatWindowVM = _floatWindow.GetViewModel(); foreach (var item in _draggedItems) { DockHelper.Remove(floatWindowVM, item); } _floatWindow = null; Win32.ReleaseCapture(); // Exit Win32 move window loop. // Add items into target DockTabPane. _targetDockTabPane = dockTabPane; foreach (var item in _draggedItems) { item.DockState = dockTabPaneVM.DockState; dockTabPaneVM.Items.Add(item); } // Make sure the current item is selected in DockTabPane. _dockStrategy.Activate(_activeItem); // When the Win32 move window loop exits, the DockControl receives a LostMouseCapture // event. --> Defer dragging of the DockTabItems. _dockControl.Dispatcher.BeginInvoke(new Action(() => { if (!_dockControl.IsMouseCaptured) { if (!_dockControl.CaptureMouse()) { // Failed to capture the mouse. EndDrag(false); return; } _dockControl.LostMouseCapture += OnLostMouseCapture; _dockControl.MouseMove += OnMouseMove; _dockControl.MouseLeftButtonUp += OnMouseLeftButtonUp; _dockControl.PreviewKeyDown += OnPreviewKeyDown; _targetDockTabPane.PreviewKeyDown += OnPreviewKeyDown; DragDockTabItems(); } })); HideBorderDockIndicators(); HidePaneIndicators(); _dockControl.UpdateFloatWindows(); _layoutChanged = true; }
private void DragDockTabItemsIntoFloatWindow() { Debug.Assert(_floatWindow == null); if (_targetDockTabPane != null) { ClearTranslateTransform(); _targetDockTabPane.PreviewKeyDown -= OnPreviewKeyDown; _targetDockTabPane = null; } _dockControl.LostMouseCapture -= OnLostMouseCapture; _dockControl.MouseLeftButtonUp -= OnMouseLeftButtonUp; _dockControl.MouseMove -= OnMouseMove; _dockControl.PreviewKeyDown -= OnPreviewKeyDown; _dockControl.ReleaseMouseCapture(); // Remove the dragged items from their current location. foreach (var item in _draggedItems) { DockHelper.Remove(_dockStrategy.DockControl.RootPane, item); foreach (var floatWindow in _dockStrategy.DockControl.FloatWindows) { DockHelper.Remove(floatWindow, item); } DockHelper.Remove(_dockStrategy.DockControl.AutoHideLeft, item); DockHelper.Remove(_dockStrategy.DockControl.AutoHideRight, item); DockHelper.Remove(_dockStrategy.DockControl.AutoHideTop, item); DockHelper.Remove(_dockStrategy.DockControl.AutoHideBottom, item); } // Move items into a new FloatWindow. foreach (var item in _draggedItems) { item.DockState = DockState.Float; } var newPaneVM = _dockStrategy.CreateDockTabPane(_draggedItems[0], DockState.Float); for (int i = 1; i < _draggedItems.Count; i++) { newPaneVM.Items.Add(_draggedItems[i]); } var floatWindowVM = _dockStrategy.CreateFloatWindow(); floatWindowVM.RootPane = newPaneVM; _dockStrategy.DockControl.FloatWindows.Add(floatWindowVM); _dockStrategy.Activate(_activeItem); _dockStrategy.Cleanup(); // Get the newly created FloatWindow (view) from the DockControl. _floatWindow = GetFloatWindow(floatWindowVM); Debug.Assert(_floatWindow != null); LimitFloatWindowSize(_floatWindow, _initialSize); // Limit mouse offset to FloatWindow size. double actualWidth = _floatWindow.ActualWidth; if (actualWidth > 0) { _mouseOffset.X = Math.Min(_mouseOffset.X, actualWidth / 2); } Point position = GetFloatWindowPosition(); _floatWindow.Left = position.X; _floatWindow.Top = position.Y; // Wait until FloatWindow is loaded, initiate the Win32 move window loop. _floatWindow.Dispatcher.BeginInvoke(new Action(() => { if (_floatWindow != null) { LimitFloatWindowSize(_floatWindow, _initialSize); // Limit mouse offset to FloatWindow size. _mouseOffset.X = Math.Min(_mouseOffset.X, _floatWindow.ActualWidth / 2); _mouseOffset.Y = Math.Max(_mouseOffset.Y, 8); Point pos = GetFloatWindowPosition(); _floatWindow.Left = pos.X; _floatWindow.Top = pos.Y; if (Mouse.LeftButton == MouseButtonState.Pressed) { _floatWindow.DragMove(); } else { EndDrag(true); } } }), DispatcherPriority.Loaded); // Important: Action needs to be invoked before input. }
/// <summary> /// Starts a drag operation. /// </summary> /// <param name="floatWindow">The <see cref="FloatWindow"/> to be dragged.</param> /// <param name="dockTabPane">The <see cref="DockTabPane"/> to be dragged.</param> /// <param name="dockTabItem">The <see cref="DockTabItem"/> to be dragged.</param> /// <returns> /// <see langword="true" /> if the drag operation has been started; otherwise, /// <see langword="false" /> if the drag operation could not be started (e.g. because the /// mouse could not be captured). /// </returns> private bool BeginDrag(FloatWindow floatWindow, DockTabPane dockTabPane, DockTabItem dockTabItem) { _dockStrategy = _dockControl.GetViewModel()?.DockStrategy; if (_dockStrategy == null || _dockStrategy.DockControl.IsLocked) { Reset(); return(false); } FrameworkElement element = null; IDockTabPane draggedPane = null; IDockTabItem draggedItem = null; if (floatWindow != null) { // User is dragging a FloatWindow. // (Note: Dragging of FloatWindows with nested layouts is not supported.) draggedPane = floatWindow.GetViewModel()?.RootPane as IDockTabPane; element = floatWindow; _floatWindow = floatWindow; _initialSize = floatWindow.RenderSize; // Start dragging immediately. _dragDeltaExceeded = true; } else if (dockTabItem != null) { // User is dragging a DockTabItem in a DockTabPanel. draggedItem = dockTabItem.GetViewModel(); element = dockTabItem; _targetDockTabPane = dockTabPane; _initialSize = dockTabPane.RenderSize; // Start dragging when threshold is exceeded. _initialMousePosition = WindowsHelper.GetMousePosition(_dockControl); _dragDeltaExceeded = false; } else if (dockTabPane != null) { // User is dragging a DockTabPane. draggedPane = dockTabPane.GetViewModel(); element = dockTabPane; _initialSize = dockTabPane.RenderSize; _initialMousePosition = WindowsHelper.GetMousePosition(_dockControl); // Start dragging when threshold is exceeded. _initialMousePosition = WindowsHelper.GetMousePosition(_dockControl); _dragDeltaExceeded = false; } if (draggedPane == null && draggedItem == null) { Reset(); return(false); } // When the user is dragging the FloatWindow, the mouse is captured by Win32 move window // loop. When dragging a DockTabPane or DockTabItem, the mouse needs to be // captured to receive mouse events. if (_floatWindow == null) { if (!_dockControl.CaptureMouse()) { // Failed to capture the mouse. Reset(); return(false); } _dockControl.LostMouseCapture += OnLostMouseCapture; _dockControl.MouseLeftButtonUp += OnMouseLeftButtonUp; _dockControl.MouseMove += OnMouseMove; _dockControl.PreviewKeyDown += OnPreviewKeyDown; if (_targetDockTabPane != null) { _targetDockTabPane.PreviewKeyDown += OnPreviewKeyDown; } } _dockStrategy.Begin(); if (draggedPane != null) { _dockStrategy.Activate(draggedPane); _activeItem = draggedPane.SelectedItem; foreach (var item in draggedPane.Items) { if (item.DockState == draggedPane.DockState) { _draggedItems.Add(item); } } } else { Debug.Assert(draggedItem != null); _dockStrategy.Activate(draggedItem); _activeItem = draggedItem; _draggedItems.Add(draggedItem); } Debug.Assert(_draggedItems.Count > 0); // Determine whether dragged items may end in a FloatWindow. _canFloat = CanFloat(); // Store the mouse offset relative to the dragged element. _mouseOffset = (Vector)WindowsHelper.GetMousePosition(element); // Remember information needed for a rollback. ReplaceItemsWithProxies(draggedPane ?? _targetDockTabPane.GetViewModel()); _originalDockState = _draggedItems[0].DockState; BackupFloatWindowPosition(); // Override mouse cursors. (Mouse cursor should not change to caret over text editor.) Mouse.OverrideCursor = Cursors.Arrow; return(true); }
/// <summary> /// Unregisters the specified <see cref="DockTabPane"/>. /// </summary> /// <param name="dockTabPane">The <see cref="DockTabPane"/> to remove.</param> internal void Unregister(DockTabPane dockTabPane) { _dockTabPanes.Remove(dockTabPane); }
//internal static IDockAnchorPane GetViewModel(this DockAnchorPane view) //{ // return GetViewModel<IDockAnchorPane>(view); //} //internal static IDockSplitPane GetViewModel(this DockSplitPane view) //{ // return GetViewModel<IDockSplitPane>(view); //} internal static IDockTabPane GetViewModel(this DockTabPane view) { return(GetViewModel <IDockTabPane>(view)); }