Exemple #1
0
        private void Commit()
        {
            if (_layoutChanged)
            {
                if (IsDraggingDockTabItems)
                {
                    // Dragging ended in DockTabPanel.
                    RestoreFloatWindowPosition();
                }
                else if (_floatWindow != null)
                {
                    // Dragging ended outside of a DockTabPanel. Check the dock indicators to find the
                    // desired target position.
                    IDockPane    target   = null;
                    DockPosition position = DockPosition.None;
                    if (HasResult(_borderDockIndicators))
                    {
                        target   = _dockStrategy.DockControl.RootPane;
                        position = _borderDockIndicators.Result;
                    }
                    else if (HasResult(_paneDockIndicators))
                    {
                        target   = DockHelper.GetViewModel <IDockPane>(_paneDockIndicators.Target);
                        position = _paneDockIndicators.Result;
                    }

                    if (position != DockPosition.None && target != null)
                    {
                        // User has dropped FloatWindow on a DockIndicator.
                        // --> Dock content.
                        var floatWindowVM = _floatWindow.GetViewModel();
                        foreach (var item in _draggedItems)
                        {
                            DockHelper.Remove(floatWindowVM, item);
                            item.DockState = DockState.Hide;
                        }

                        var dockTabPane = _dockStrategy.CreateDockTabPane(_draggedItems[0], DockState.Hide);
                        for (int i = 1; i < _draggedItems.Count; i++)
                        {
                            dockTabPane.Items.Add(_draggedItems[i]);
                        }

                        _dockStrategy.Dock(dockTabPane, target, position);
                        RestoreFloatWindowPosition();
                    }
                    else
                    {
                        // The final state is DockState.Float.
                        if (!_canFloat && _originalDockState != DockState.Float)
                        {
                            // DockState.Float is not allowed.
                            Rollback();
                            return;
                        }
                    }
                }
            }

            // Keep the items at their new position.
            // --> Remove the item proxies.
            var dockState = _draggedItems[0].DockState;

            RemoveItemProxies(dockState);
            if (_layoutChanged && dockState == DockState.Dock)
            {
                // The position within the DockControl may have changed. The assignment to the
                // auto-hide bar is no longer valid.
                // --> Also remove item proxies from auto-hide bars.
                RemoveItemProxies(DockState.AutoHide);
            }

            // Restore the original dock state of the dragged items.
            RestoreItemsFromProxies();
        }
Exemple #2
0
        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.
        }
Exemple #3
0
        /// <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;
        }
Exemple #4
0
        public static void Load(IDockControl dockControl, XElement storedLayout /*, bool keepDockTabItems */)
        {
            ///// <param name="keepDockTabItems">
            ///// If set to <see langword="true"/> all existing <see cref="IDockTabItem"/>s are kept. If
            ///// set to <see langword="false"/>, all current <see cref="IDockTabItem"/>s are closed
            ///// before the new layout is loaded.
            ///// </param>

            if (dockControl == null)
            {
                throw new ArgumentNullException(nameof(dockControl));
            }
            if (storedLayout == null)
            {
                throw new ArgumentNullException(nameof(storedLayout));
            }

            var dockStrategy = dockControl.DockStrategy;

            if (dockStrategy == null)
            {
                throw new ArgumentException("The IDockControl does not have a DockStrategy.");
            }

            const bool keepNonPersistentItems = true;  // Non-persistent items are usually documents and should be kept.
            const bool keepPersistentItems    = false; // Persistent items are usually tool windows.

            // Remember current dock items (visible and hidden items).
            var items = dockControl.GetDockElements()
                        .OfType <IDockTabItem>()
                        .Distinct()
                        .ToArray();

            // Validate DockIds.
            foreach (var item in items)
            {
                if (item.DockId == null)
                {
                    throw new DockException("Could not load docking layout. IDockTabItem does not have a valid DockId.");
                }
            }

            // Check for duplicate DockIds.
            bool duplicateDockIds = items.GroupBy(item => item.DockId)
                                    .Select(group => group.Count())
                                    .Any(count => count > 1);

            if (duplicateDockIds)
            {
                throw new DockException("Could not load docking layout. Two or more IDockTabItems have the same DockId.");
            }

            var context = new DeserializationContext {
                DockControl = dockControl
            };

            dockStrategy.Begin();
            try
            {
                // Remember current IDockTabItems.
                // context.OldItems stores all (because OldItems is used in LoadDockTabItem).
                // Another list stores only the old items which are visible.
                var oldVisibleItems = new List <IDockTabItem>();
                foreach (var item in items)
                {
                    context.OldItems[item.DockId] = item;

                    if (item.DockState != DockState.Hide)
                    {
                        oldVisibleItems.Add(item);
                    }
                }

                // Load IDockTabItems. Do not add to the dock control yet.
                foreach (var itemXElement in storedLayout.Elements("DockTabItems").Elements())
                {
                    var item = LoadDockTabItem(context, itemXElement, onlyReference: false);
                    if (item != null)
                    {
                        context.NewItems[item.DockId] = item;
                    }
                }

                // Try to close all IDockTabItems which we will not keep or which will be hidden.
                // We keep a list of items which we need to keep open.
                var oldItemsToShow = new List <IDockTabItem>();
                foreach (var oldDockTabItem in oldVisibleItems)
                {
                    if (context.NewItems.ContainsKey(oldDockTabItem.DockId) &&
                        oldDockTabItem.DockState != DockState.Hide)
                    {
                        // Item remains in the layout and visible.
                        continue;
                    }

                    // Previously visible item is removed from layout or hidden.
                    // Try to close it. Items that cannot be closed will be shown at the end.
                    bool closed = false;
                    if ((oldDockTabItem.IsPersistent && !keepPersistentItems) ||
                        (!oldDockTabItem.IsPersistent && !keepNonPersistentItems))
                    {
                        if (dockStrategy.CanClose(oldDockTabItem))
                        {
                            // Successfully closed.
                            dockStrategy.Close(oldDockTabItem);
                            closed = true;
                        }
                    }

                    if (!closed)
                    {
                        oldItemsToShow.Add(oldDockTabItem);
                    }
                }

                // The DockControl still contains the old layout with the previous IDockPane
                // view model. The old view models are still attached to the DockControl and
                // react to changes, which may cause the wrong screen conduction.
                // --> Detach IDockTabItems from old layout.
                foreach (var item in items)
                {
                    DockHelper.Remove(dockControl, item);
                }

                dockControl.FloatWindows.Clear();
                dockControl.AutoHideLeft.Clear();
                dockControl.AutoHideRight.Clear();
                dockControl.AutoHideTop.Clear();
                dockControl.AutoHideBottom.Clear();

                var isLocked = (bool?)context.Checked(storedLayout.Attribute("IsLocked"));
                if (isLocked != null)
                {
                    dockControl.IsLocked = isLocked.Value;
                }

                // Load float windows.
                {
                    foreach (var xElement in storedLayout.Elements("FloatWindows").Elements())
                    {
                        var floatWindow = LoadFloatWindow(context, xElement);
                        if (floatWindow != null)
                        {
                            dockControl.FloatWindows.Add(floatWindow);
                        }
                    }
                }

                // Load auto-hide panes.
                {
                    var autoHideBars = new[]
                    {
                        new { Bar = dockControl.AutoHideLeft, Name = "AutoHideLeft" },
                        new { Bar = dockControl.AutoHideRight, Name = "AutoHideRight" },
                        new { Bar = dockControl.AutoHideTop, Name = "AutoHideTop" },
                        new { Bar = dockControl.AutoHideBottom, Name = "AutoHideBottom" },
                    };

                    foreach (var bar in autoHideBars)
                    {
                        foreach (var xElement in storedLayout.Elements(bar.Name).Elements())
                        {
                            var dockPane = LoadDockPane(context, xElement);
                            if (dockPane != null)
                            {
                                bar.Bar.Add((IDockTabPane)dockPane);
                            }
                        }
                    }
                }

                // Load root pane. (We do this after loading the float windows and auto-hide bars,
                // because the dock strategy might want to activate an item in a float window or
                // auto-hide bar).
                dockControl.RootPane = LoadDockPane(context, storedLayout.Elements("RootPane").Elements().FirstOrDefault());

                // Run cleanup to update IsVisible flags. Those should be up-to-date before calling
                // Show() to find good default dock target positions.
                dockStrategy.Cleanup();

                // This is not done in cleanup if we are inside Begin()/End().
                dockControl.ActiveDockTabPane = null;
                dockControl.ActiveDockTabItem = null;

                // Show all old items that are not visible in the loaded layout but could not be closed.
                foreach (var item in oldItemsToShow)
                {
                    dockStrategy.Show(item);
                }

                // Activate item.
                if (context.ActiveItem != null)
                {
                    dockStrategy.Show(context.ActiveItem);
                }

                context.ResetLineInfo();
            }
            catch (Exception exception)
            {
                var message = "Could not load docking layout.";

                if (context.LineInfo != null && context.LineInfo.HasLineInfo())
                {
                    message += Invariant($" Error at line {context.LineInfo.LineNumber}, column {context.LineInfo.LinePosition}.");
                }

                message += " See inner exception for more details.";

                throw new DockException(message, exception);
            }
            finally
            {
                dockStrategy.End();
            }
        }