Esempio n. 1
0
        /// <summary>
        /// Moves the current focus in the focus chain.
        /// </summary>
        /// <param name="direction">The change in position, relative to the current position.</param>
        /// <param name="resetAnchor">If true, resets the selected text anchor.</param>
        /// <param name="isMoved">True upon return if the focus was moved.</param>
        public virtual void MoveFocus(int direction, bool resetAnchor, out bool isMoved)
        {
            ulong OldFocusHash = FocusHash;

            int OldFocusIndex = FocusChain.IndexOf(Focus);

            Debug.Assert(OldFocusIndex >= 0 && OldFocusIndex < FocusChain.Count);

            int NewFocusIndex = OldFocusIndex + direction;

            if (NewFocusIndex < 0)
            {
                NewFocusIndex = 0;
            }
            else if (NewFocusIndex >= FocusChain.Count)
            {
                NewFocusIndex = FocusChain.Count - 1;
            }

            Debug.Assert(NewFocusIndex >= 0 && NewFocusIndex < FocusChain.Count);

            if (OldFocusIndex != NewFocusIndex)
            {
                ChangeFocus(direction, OldFocusIndex, NewFocusIndex, resetAnchor, out bool IsRefreshed);
                isMoved = true;
            }
            else
            {
                isMoved = false;
            }

            Debug.Assert(isMoved || OldFocusHash == FocusHash);
        }
Esempio n. 2
0
        /// <summary>
        /// Moves the focus up or down.
        /// The starting point is the center of the area covered by the current focus.
        /// </summary>
        /// <param name="distance">The distance to cross.</param>
        /// <param name="resetAnchor">If true, resets the selected text anchor.</param>
        /// <param name="isMoved">True if the focus has changed.</param>
        public virtual void MoveFocusVertically(double distance, bool resetAnchor, out bool isMoved)
        {
            ulong OldFocusHash = FocusHash;

            int    OldFocusIndex          = FocusChain.IndexOf(Focus);
            int    NewFocusIndex          = -1;
            double BestVerticalDistance   = 0;
            double BestHorizontalDistance = 0;

            FindClosestFocusVertical(distance, OldFocusIndex, ref NewFocusIndex, ref BestVerticalDistance, ref BestHorizontalDistance);

            // Always choose an extremum cell view if all are on the wrong side of the target.
            if (NewFocusIndex < 0)
            {
                NewFocusIndex = (distance < 0) ? 0 : FocusChain.Count - 1;
            }

            if (NewFocusIndex != OldFocusIndex)
            {
                Debug.Assert(NewFocusIndex >= MinFocusMove + OldFocusIndex && NewFocusIndex <= MaxFocusMove + OldFocusIndex);

                ChangeFocus(NewFocusIndex - OldFocusIndex, OldFocusIndex, NewFocusIndex, resetAnchor, out bool IsRefreshed);
                isMoved = true;
            }
            else
            {
                isMoved = false;
            }

            Debug.Assert(isMoved || OldFocusHash == FocusHash);
        }
Esempio n. 3
0
        /// <summary>
        /// Force the comment attached to the node with the focus to show, if empty, and move the focus to this comment.
        /// </summary>
        public virtual void ForceShowComment(out bool isMoved)
        {
            IFocusNodeState State = Focus.CellView.StateView.State;
            Document        Documentation;

            if (State is IFocusOptionalNodeState AsOptionalNodeState)
            {
                Debug.Assert(AsOptionalNodeState.ParentInner.IsAssigned);
                Documentation = AsOptionalNodeState.Node.Documentation;
            }
            else
            {
                Documentation = State.Node.Documentation;
            }

            isMoved = false;
            ulong OldFocusHash = FocusHash;

            if (!(Focus is IFocusCommentFocus))
            {
                string Text = CommentHelper.Get(Documentation);
                if (Text == null)
                {
                    IFocusNodeStateView StateView = Focus.CellView.StateView;
                    ForcedCommentStateView = StateView;

                    Refresh(Controller.RootState);
                    Debug.Assert(ForcedCommentStateView == null);

                    for (int i = 0; i < FocusChain.Count; i++)
                    {
                        if (FocusChain[i] is IFocusCommentFocus AsCommentFocus && AsCommentFocus.CellView.StateView == StateView)
                        {
                            int OldFocusIndex = FocusChain.IndexOf(Focus);
                            Debug.Assert(OldFocusIndex >= 0); // The old focus must have been preserved.

                            int NewFocusIndex = i;

                            ChangeFocus(NewFocusIndex - OldFocusIndex, OldFocusIndex, NewFocusIndex, true, out bool IsRefreshed);
                            Debug.Assert(!IsRefreshed); // Refresh must not be done twice.

                            isMoved = true;
                            break;
                        }
                    }

                    Debug.Assert(isMoved);
                }
            }

            if (isMoved)
            {
                ResetSelection();
            }

            Debug.Assert(isMoved || OldFocusHash == FocusHash);
        }
Esempio n. 4
0
        /// <summary>
        /// Sets the focus to the visible cell view corresponding to a location.
        /// </summary>
        /// <param name="x">X-coordinate of the location where to set the focus.</param>
        /// <param name="y">Y-coordinate of the location where to set the focus.</param>
        /// <param name="resetAnchor">If true, resets the selected text anchor.</param>
        /// <param name="isMoved">True if the focus was moved.</param>
        public virtual void SetFocusToPoint(double x, double y, bool resetAnchor, out bool isMoved)
        {
            isMoved = false;
            ulong OldFocusHash = FocusHash;
            int   OldIndex     = FocusChain.IndexOf(Focus);
            int   NewIndex     = -1;

            // Takes page margins and padding into account.
            DrawContext.ToRelativeLocation(ref x, ref y);

            for (int i = 0; i < FocusChain.Count; i++)
            {
                ILayoutFocus TestFocus = (ILayoutFocus)FocusChain[i];
                if (TestFocus.CellView.CellRect.IsPointInRect(x, y))
                {
                    NewIndex = i;
                    break;
                }
            }

            if (NewIndex >= 0)
            {
                if (NewIndex != OldIndex)
                {
                    ChangeFocus(NewIndex - OldIndex, OldIndex, NewIndex, resetAnchor, out bool IsRefreshed);
                }

                if (Focus is ILayoutTextFocus AsTextFocus)
                {
                    Point CellOrigin = Focus.CellView.CellOrigin;
                    Size  CellSize   = Focus.CellView.CellSize;

                    double XRelativeToCell = x - CellOrigin.X.Draw;
                    double YRelativeToCell = y - CellOrigin.Y.Draw;
                    Debug.Assert(XRelativeToCell >= 0 && XRelativeToCell < CellSize.Width.Draw);
                    Debug.Assert(YRelativeToCell >= 0 && YRelativeToCell < CellSize.Height.Draw);

                    string Text             = GetFocusedText(AsTextFocus);
                    int    NewCaretPosition = DrawContext.GetCaretPositionInText(XRelativeToCell, Text, FocusedTextStyle, CaretMode, Measure.Floating);
                    Debug.Assert(NewCaretPosition >= 0 && NewCaretPosition <= MaxCaretPosition);

                    SetTextCaretPosition(Text, NewCaretPosition, resetAnchor, out isMoved);
                }

                isMoved = true;
            }

            Debug.Assert(isMoved || OldFocusHash == FocusHash);
        }
Esempio n. 5
0
        /// <summary>
        /// Moves the focus to the beginning or end of a line.
        /// The starting point is the center of the area covered by the current focus.
        /// </summary>
        /// <param name="direction">-1 for the beginning of the line, +1 for the end.</param>
        /// <param name="resetAnchor">If true, resets the selected text anchor.</param>
        /// <param name="isMoved">True if the focus has changed.</param>
        public virtual void MoveFocusHorizontally(int direction, bool resetAnchor, out bool isMoved)
        {
            Debug.Assert(direction != 0);

            ulong OldFocusHash = FocusHash;

            int    OldFocusIndex       = FocusChain.IndexOf(Focus);
            int    NewFocusIndex       = -1;
            double BestSquaredDistance = 0;

            FindClosestFocusHorizontal(direction, ref NewFocusIndex, ref BestSquaredDistance);

            if (NewFocusIndex >= 0 && NewFocusIndex != OldFocusIndex)
            {
                Debug.Assert(NewFocusIndex >= MinFocusMove + OldFocusIndex && NewFocusIndex <= MaxFocusMove + OldFocusIndex);

                ChangeFocus(direction, OldFocusIndex, NewFocusIndex, resetAnchor, out bool IsRefreshed);
                isMoved = true;

                resetAnchor = true;
            }
            else
            {
                isMoved = false;
            }

            // Also move the caret.
            if (Focus is ILayoutTextFocus AsTextFocus)
            {
                string Text = GetFocusedText(AsTextFocus);
                bool   IsCaretMoved;

                if (direction < 0)
                {
                    SetTextCaretPosition(Text, 0, resetAnchor, out IsCaretMoved);
                }
                else
                {
                    SetTextCaretPosition(Text, Text.Length, resetAnchor, out IsCaretMoved);
                }

                isMoved |= IsCaretMoved;
            }

            Debug.Assert(isMoved || OldFocusHash == FocusHash);
        }
        private protected virtual void UpdateFocusChain(IFocusNodeState state, Node focusedNode, IFocusFrame focusedFrame)
        {
            FocusFocusList      NewFocusChain = CreateFocusChain();
            IFocusNodeState     RootState     = Controller.RootState;
            IFocusNodeStateView RootStateView = (IFocusNodeStateView)StateViewTable[RootState];

            IFocusFocus MatchingFocus = null;

            RootStateView.UpdateFocusChain(NewFocusChain, focusedNode, focusedFrame, ref MatchingFocus);

            // Ensured by all templates having at least one preferred (hence focusable) frame.
            Debug.Assert(NewFocusChain.Count > 0);

            // First run, initialize the focus to the first focusable cell.
            if (Focus == null)
            {
                Debug.Assert(FocusChain == null);
                Focus = NewFocusChain[0];
                ResetCaretPosition(0, true);
            }
            else if (MatchingFocus != null)
            {
                Focus = MatchingFocus;
                UpdateMaxCaretPosition(); // The focus didn't change, but the content may have.
            }
            else
            {
                RecoverFocus(state, NewFocusChain); // The focus has forcibly changed.
            }
            FocusChain = NewFocusChain;
            DebugObjects.AddReference(NewFocusChain);

            Debug.Assert(Focus != null);
            Debug.Assert(FocusChain.Contains(Focus));

            SelectionAnchor    = Focus.CellView.StateView;
            SelectionExtension = 0;
        }