예제 #1
0
        /// <summary>
        /// Inserts the specified text at the current cursor position, if possible
        /// </summary>
        private async Task InsertText(XmlCursor cursor, string text, XmlRules xmlRules)
        {
            XmlCursorPos insertPos;

            // If something is selected, then delete it first, because it will be replaced by the new text
            XmlCursor deleteArea = cursor.Clone();
            await deleteArea.OptimizeSelection();

            var deleteResult = await XmlCursorSelectionHelper.DeleteSelection(deleteArea);

            if (deleteResult.Success)
            {
                insertPos = deleteResult.NewCursorPosAfterDelete;
            }
            else
            {
                insertPos = cursor.StartPos.Clone();
            }

            // insert the specified text at the cursor position
            var replacementNode = InsertAtCursorPosHelper.InsertText(insertPos, text, xmlRules).ReplaceNode;

            if (replacementNode != null)
            {
                // Text could not be inserted because a node input was converted from text input.
                // Example: In the AIML template, * is pressed, and a <star> is inserted there instead
                InsertAtCursorPosHelper.InsertXmlNode(insertPos, replacementNode, xmlRules, false);
            }

            // then the cursor is only one line behind the inserted text
            await cursor.SetPositions(insertPos.ActualNode, insertPos.PosOnNode, insertPos.PosInTextNode, throwChangedEventWhenValuesChanged : false);
        }
예제 #2
0
        /// <summary>
        /// Finds out if the node or one of its parent nodes is selected
        /// </summary>
        public static bool IsThisNodeInsideSelection(XmlCursor cursor, System.Xml.XmlNode node)
        {
            // Check if the node itself or one of its parents is directly selected
            if (cursor.StartPos.IsNodeInsideSelection(node))
            {
                return(true);
            }
            if (cursor.EndPos.IsNodeInsideSelection(node))
            {
                return(true);
            }

            if (cursor.StartPos.Equals(cursor.EndPos)) // Both positions are the same, so a maximum of one single node is selected
            {
                return(cursor.StartPos.IsNodeInsideSelection(node));
            }
            else // Both positions are not equal, so something may be selected
            {
                if ((cursor.StartPos.ActualNode == node) || (cursor.EndPos.ActualNode == node)) // Start or EndNode of the selection is this node
                {
                    if (node is System.Xml.XmlText) // is a text node
                    {
                        return(true);
                    }
                    else // not a text node
                    {
                        return(false);
                    }
                }
                else
                {
                    if (cursor.StartPos.LiesBehindThisPos(node))   // Node is behind the starting position
                    {
                        if (cursor.EndPos.LiesBeforeThisPos(node)) // Node is located between Startpos and Endepos
                        {
                            return(true);
                        }
                        else // Node is behind Startpos but also behind Endpos
                        {
                            return(false);
                        }
                    }
                    else // Node is not behind the start pos
                    {
                        return(false);
                    }
                }
            }
        }
예제 #3
0
 public async Task UnDo()
 {
     if (this.UndoHandler == null)
     {
         throw new ApplicationException("No Undo-Handler attached, but Undo invoked!");
     }
     else
     {
         XmlCursor c = this.UndoHandler.Undo();
         if (c != null) // If a CursorPos was stored for this undo step
         {
             await this.CursorRaw.SetPositions(
                 c.StartPos.ActualNode, c.StartPos.PosOnNode, c.StartPos.PosInTextNode,
                 c.EndPos.ActualNode, c.EndPos.PosOnNode, c.EndPos.PosInTextNode,
                 throwChangedEventWhenValuesChanged : true);
         }
         await this.FireContentChangedEvent(needToSetFocusOnEditorWhenLost : false, forceFullRepaint : false);
     }
 }
예제 #4
0
        /// <summary>
        /// FInserts the specified node at the current cursor position, if possible
        /// </summary>
        private async Task XMLNodeEinfuegen(XmlCursor cursor, XmlNode node, XmlRules xmlRules, bool setNewCursorPosBehindNewInsertedNode)
        {
            // If something is selected, then delete it first, because it will be replaced by the new text
            XmlCursor deleteArea = cursor.Clone();
            await deleteArea.OptimizeSelection();

            var deleteResult = await XmlCursorSelectionHelper.DeleteSelection(deleteArea);

            if (deleteResult.Success)
            {
                await cursor.SetPositions(deleteResult.NewCursorPosAfterDelete.ActualNode, deleteResult.NewCursorPosAfterDelete.PosOnNode, deleteResult.NewCursorPosAfterDelete.PosInTextNode, throwChangedEventWhenValuesChanged : false);
            }

            // insert the specified node at the cursor position
            if (InsertAtCursorPosHelper.InsertXmlNode(cursor.StartPos, node, xmlRules, setNewCursorPosBehindNewInsertedNode))
            {
                // then the cursor is only one line behind the inserted
                cursor.EndPos.SetPos(cursor.StartPos.ActualNode, cursor.StartPos.PosOnNode, cursor.StartPos.PosInTextNode);
            }
        }
예제 #5
0
        /// <summary>
        /// Delete the node or the character behind the cursor
        /// </summary>
        public async Task <bool> ActionDeleteNodeOrSignBehindCursorPos(XmlCursorPos position, SetUndoSnapshotOptions setUnDoSnapshot)
        {
            if (!this.ActionsAllowed)
            {
                return(false);
            }

            if (setUnDoSnapshot == SetUndoSnapshotOptions.Yes)
            {
                this.editorState.UndoHandler.SetSnapshot("delete", this.editorState.CursorRaw);
            }

            var deleteArea = new XmlCursor();

            deleteArea.StartPos.SetPos(position.ActualNode, position.PosOnNode, position.PosInTextNode);
            var endPos = deleteArea.StartPos.Clone();
            await CursorPosMoveHelper.MoveRight(endPos, this.editorState.RootNode, this.xmlRules);

            deleteArea.EndPos.SetPos(endPos.ActualNode, endPos.PosOnNode, endPos.PosInTextNode);
            await deleteArea.OptimizeSelection();

            if (deleteArea.StartPos.ActualNode == this.editorState.RootNode)
            {
                return(false);                                                             // You must not delete the rootnot
            }
            var deleteResult = await XmlCursorSelectionHelper.DeleteSelection(deleteArea);

            if (deleteResult.Success)
            {
                // After successful deletion the new CursorPos is retrieved here
                await this.editorState.CursorRaw.SetPositions(deleteResult.NewCursorPosAfterDelete.ActualNode, deleteResult.NewCursorPosAfterDelete.PosOnNode, deleteResult.NewCursorPosAfterDelete.PosInTextNode, throwChangedEventWhenValuesChanged : false);

                await this.editorState.FireContentChangedEvent(needToSetFocusOnEditorWhenLost : false, forceFullRepaint : false);

                return(true);
            }

            return(false);
        }
예제 #6
0
 public void SetSnapshot(string snapShotName, XmlCursor cursor)
 {
     this.undoSteps[pos].SnapShotName = snapShotName;
     this.undoSteps[pos].CursorBefore = cursor;
 }
예제 #7
0
        /// <summary>
        /// Returns the selected XML content as string
        /// </summary>
        public static async Task <string> GetSelectionAsString(XmlCursor cursor)
        {
            if (cursor.IsSomethingSelected)
            {
                var result = new StringBuilder();

                var optimized = cursor.Clone();
                await optimized.OptimizeSelection();

                System.Xml.XmlNode node = optimized.StartPos.ActualNode; // begin at the start node

                // Include the start node in the result
                switch (optimized.StartPos.PosOnNode)
                {
                case XmlCursorPositions.CursorOnNodeEndTag:
                case XmlCursorPositions.CursorOnNodeStartTag:
                case XmlCursorPositions.CursorInFrontOfNode:
                    result.Append(node.OuterXml);      // take the entire start node
                    break;

                case XmlCursorPositions.CursorBehindTheNode:
                case XmlCursorPositions.CursorInsideTheEmptyNode:
                    break;

                case XmlCursorPositions.CursorInsideTextNode:     // take only a part of the text
                    string textPart = node.InnerText;

                    int start  = optimized.StartPos.PosInTextNode;
                    int length = textPart.Length - start;

                    if (node == optimized.EndPos.ActualNode)     // If this text node is both start and end node
                    {
                        switch (optimized.EndPos.PosOnNode)
                        {
                        case XmlCursorPositions.CursorOnNodeEndTag:
                        case XmlCursorPositions.CursorBehindTheNode:
                            // Length stays to the end of the node
                            break;

                        case XmlCursorPositions.CursorOnNodeStartTag:
                        case XmlCursorPositions.CursorInsideTheEmptyNode:
                        case XmlCursorPositions.CursorInFrontOfNode:
                            throw new ApplicationException($"XMLCursor.GetSelectionAsString: implausible EndPos.PosOnNode '{optimized.EndPos.PosOnNode}' for StartPos.CursorInsideTextNode");

                        case XmlCursorPositions.CursorInsideTextNode:
                            // Not quite to the end of the text
                            if (optimized.StartPos.PosInTextNode > optimized.EndPos.PosInTextNode)
                            {
                                throw new ApplicationException("XMLCursor.GetSelectionAsString: optimized.StartPos.PosInTextNode > optimized.EndPos.PosInTextNode");
                            }
                            else
                            {
                                // Subtract the text from the length after selection
                                length -= (textPart.Length - optimized.EndPos.PosInTextNode);
                            }
                            break;

                        default:
                            throw new ApplicationException($"XMLCursor.GetSelectionAsString: unhandled optimized.EndPos.PosOnNode'{optimized.EndPos.PosOnNode}' for StartPos.CursorInsideTextNode");
                        }
                    }
                    textPart = textPart.Substring(start, length);
                    result.Append(textPart);
                    break;

                default:
                    throw new ApplicationException($"XMLCursor.GetSelectionAsStringg: unhandled optimized.StartPos.PosOnNode'{optimized.StartPos.PosOnNode}'");
                }

                if (optimized.StartPos.ActualNode != optimized.EndPos.ActualNode) // If more nodes are selected after the start node
                {
                    do
                    {
                        node = node.NextSibling; // to the next node...

                        if (node != null)
                        {
                            // Include the node in the result
                            if (node == optimized.EndPos.ActualNode) // This node is the EndNode
                            {
                                switch (optimized.EndPos.PosOnNode)
                                {
                                case XmlCursorPositions.CursorOnNodeEndTag:
                                case XmlCursorPositions.CursorOnNodeStartTag:
                                case XmlCursorPositions.CursorBehindTheNode:
                                    result.Append(node.OuterXml);     // Include node 1:1 in result
                                    break;

                                case XmlCursorPositions.CursorInsideTextNode:
                                    // TRake the beginning of the text node
                                    string textPart = node.InnerText;
                                    result.Append(textPart.Substring(0, optimized.EndPos.PosInTextNode + 1));
                                    break;

                                case XmlCursorPositions.CursorInsideTheEmptyNode:
                                    throw new ApplicationException($"XMLCursor.GetSelectionAsString: implausible optimized.EndPos.PosOnNode '{optimized.EndPos.PosOnNode}' for StartPos.Node != EndPos.Node");

                                default:
                                    throw new ApplicationException($"XMLCursor.GetSelectionAsString: implausible optimized.StartPos.PosOnNode'{optimized.StartPos.PosOnNode}' for StartPos.Node != EndPos.Node");
                                }
                            }
                            else // Include node 1:1 in result
                            {
                                result.Append(node.OuterXml);
                            }
                        }
                    } while ((node != optimized.EndPos.ActualNode) && (node != null)); // ... until the end node is reached

                    if (node == null)
                    {
                        throw new ApplicationException("Endnode was not reachable as NextSibling from Startnode");
                    }
                }
                return(result.ToString());
            }
            else
            {
                return(string.Empty); // nothing is selected at all
            }
        }
예제 #8
0
 protected abstract Task <PaintContext> PaintInternal(PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, IGraphics gfx, PaintModes paintMode, int depth);
예제 #9
0
        /// <summary>
        /// Deletes the characters and nodes between StartPos and EndPos of the cursor
        /// </summary>
        internal static async Task <DeleteSelectionResult> DeleteSelection(XmlCursor cursor)
        {
            // If the cursor contains no selection at all
            if (!cursor.IsSomethingSelected)
            {
                return(new DeleteSelectionResult
                {
                    NewCursorPosAfterDelete = cursor.StartPos.Clone(), // Cursor is not changed
                    Success = false                                    // nothing deleted
                });
            }
            else
            {
                if (cursor.StartPos.ActualNode == cursor.EndPos.ActualNode) // If both nodes are identical
                {
                    switch (cursor.StartPos.PosOnNode)
                    {
                    case XmlCursorPositions.CursorOnNodeStartTag:
                    case XmlCursorPositions.CursorOnNodeEndTag:
                        // a single node is selected and should be deleted
                        System.Xml.XmlNode nodeDelete = cursor.StartPos.ActualNode; // This node should be deleted
                        System.Xml.XmlNode nodeBefore = nodeDelete.PreviousSibling; // This node is before the node to be deleted
                        System.Xml.XmlNode nodeAfter  = nodeDelete.NextSibling;     // This node lies behind the node to be deleted

                        var newPosAfterDelete = new XmlCursorPos();                 // This neighboring node will get the cursor after deletion

                        // If the node to be deleted is located between two text nodes, then these two text nodes are combined into one
                        if (nodeBefore != null && nodeAfter != null)
                        {
                            if (nodeBefore is System.Xml.XmlText && nodeAfter is System.Xml.XmlText)
                            {
                                // the node to be deleted lies between two text nodes, therefore these two text nodes are combined into one

                                // Afterwards, the cursor is positioned at the insertion point between the two text modules
                                newPosAfterDelete.SetPos(nodeBefore, XmlCursorPositions.CursorInsideTextNode, nodeBefore.InnerText.Length);

                                nodeBefore.InnerText += nodeAfter.InnerText;     // Append the text from after node to the before node

                                // Delete node to be deleted
                                nodeDelete.ParentNode.RemoveChild(nodeDelete);

                                // delete after node
                                nodeAfter.ParentNode.RemoveChild(nodeAfter);

                                return(new DeleteSelectionResult
                                {
                                    NewCursorPosAfterDelete = newPosAfterDelete,
                                    Success = true
                                });
                            }
                        }

                        // The node to be deleted is *not* between two text nodes

                        // Determine what should be selected after deletion

                        if (nodeBefore != null)
                        {
                            // After deletion, the cursor is positioned behind the previous node
                            newPosAfterDelete.SetPos(nodeBefore, XmlCursorPositions.CursorBehindTheNode);
                        }
                        else
                        {
                            if (nodeAfter != null)
                            {
                                // After deletion, the cursor is positioned before the following node
                                newPosAfterDelete.SetPos(nodeAfter, XmlCursorPositions.CursorInFrontOfNode);
                            }
                            else
                            {
                                // After deletion, the cursor is in the parent node
                                newPosAfterDelete.SetPos(nodeDelete.ParentNode, XmlCursorPositions.CursorInsideTheEmptyNode);
                            }
                        }

                        // delete the node
                        nodeDelete.ParentNode.RemoveChild(nodeDelete);
                        return(new DeleteSelectionResult
                        {
                            NewCursorPosAfterDelete = newPosAfterDelete,
                            Success = true
                        });

                    case XmlCursorPositions.CursorInFrontOfNode:
                        // Start and end of the deletion area point to the same node and the start is before the node: This only makes sense with a text node!
                        if (ToolboxXml.IsTextOrCommentNode(cursor.StartPos.ActualNode))
                        {
                            // Place the cursor in the text node before the first character and then resend
                            cursor.StartPos.SetPos(cursor.StartPos.ActualNode, XmlCursorPositions.CursorInsideTextNode, 0);
                            return(await DeleteSelection(cursor));    // resend to delete
                        }
                        else
                        {
                            // if it is not a text node, then select the whole node and send it again
                            await cursor.SetBothPositionsAndFireChangedEventIfChanged(cursor.StartPos.ActualNode, XmlCursorPositions.CursorOnNodeStartTag);

                            return(await DeleteSelection(cursor));    // resend to delete
                        }

                    case XmlCursorPositions.CursorBehindTheNode:
                        // Start and end of the deletion area point to the same node and the start is behind the node
                        if (ToolboxXml.IsTextOrCommentNode(cursor.StartPos.ActualNode))
                        {
                            // Place the cursor in the text node before the first character and then resend
                            cursor.StartPos.SetPos(cursor.StartPos.ActualNode, XmlCursorPositions.CursorInsideTextNode, cursor.StartPos.ActualNode.InnerText.Length);
                            return(await DeleteSelection(cursor));    // resend to delete
                        }
                        else
                        {
                            // if it is not a text node, then select the whole node and send it again
                            await cursor.SetBothPositionsAndFireChangedEventIfChanged(cursor.StartPos.ActualNode, XmlCursorPositions.CursorOnNodeStartTag);

                            return(await DeleteSelection(cursor));    // resend to delete
                        }

                    case XmlCursorPositions.CursorInsideTextNode:
                        // a part of a text node is to be deleted
                        // Determine the part of the text to be deleted
                        int startpos = cursor.StartPos.PosInTextNode;
                        int endpos   = cursor.EndPos.PosInTextNode;

                        if (cursor.EndPos.PosOnNode == XmlCursorPositions.CursorBehindTheNode)
                        {
                            // If the end of the selection is behind the text node, then all remaining text is selected
                            endpos = cursor.StartPos.ActualNode.InnerText.Length;
                        }

                        // If all text is selected, then delete the entire text node
                        if (startpos == 0 && endpos >= cursor.StartPos.ActualNode.InnerText.Length)
                        {
                            // The whole text node is to be deleted, this is passed on to the method for deleting individually selected nodes
                            XmlCursor nodeSelectedCursor = new XmlCursor();
                            await nodeSelectedCursor.SetBothPositionsAndFireChangedEventIfChanged(cursor.StartPos.ActualNode, XmlCursorPositions.CursorOnNodeStartTag);

                            return(await DeleteSelection(nodeSelectedCursor));
                        }
                        else
                        {
                            // Only a part of the text is to be deleted
                            string restText = cursor.StartPos.ActualNode.InnerText;
                            restText = restText.Remove(startpos, endpos - startpos);
                            cursor.StartPos.ActualNode.InnerText = restText;

                            // determine where the cursor is after deletion
                            newPosAfterDelete = new XmlCursorPos();
                            if (startpos == 0)     // The cursor is positioned before the first character
                            {
                                // then it can better be placed before the text node itself
                                newPosAfterDelete.SetPos(cursor.StartPos.ActualNode, XmlCursorPositions.CursorInFrontOfNode);
                            }
                            else
                            {
                                newPosAfterDelete.SetPos(cursor.StartPos.ActualNode, XmlCursorPositions.CursorInsideTextNode, startpos);
                            }

                            return(new DeleteSelectionResult
                            {
                                NewCursorPosAfterDelete = newPosAfterDelete,
                                Success = true
                            });
                        }

                    case XmlCursorPositions.CursorInsideTheEmptyNode:
                        if (cursor.EndPos.PosOnNode == XmlCursorPositions.CursorBehindTheNode ||
                            cursor.EndPos.PosOnNode == XmlCursorPositions.CursorInFrontOfNode)
                        {
                            XmlCursor newCursor = new XmlCursor();
                            await newCursor.SetBothPositionsAndFireChangedEventIfChanged(cursor.StartPos.ActualNode, XmlCursorPositions.CursorOnNodeStartTag, 0);

                            return(await DeleteSelection(newCursor));
                        }
                        else
                        {
                            throw new ApplicationException($"DeleteSelection:#6363S undefined Endpos '{cursor.EndPos.PosOnNode}'!");
                        }

                    default:
                        //  what else should be selected besides text and the node itself, if start node and end node are identical?
                        throw new ApplicationException($"DeleteSelection:#63346 StartPos.PosAmNode '{cursor.StartPos.PosOnNode}' not allowed!");
                    }
                }
                else // Both nodes are not identical
                {
                    // If both nodes are not identical, then remove all nodes in between until the two nodes are behind each other
                    while (cursor.StartPos.ActualNode.NextSibling != cursor.EndPos.ActualNode)
                    {
                        cursor.StartPos.ActualNode.ParentNode.RemoveChild(cursor.StartPos.ActualNode.NextSibling);
                    }

                    // delete the endnode or a part of it
                    XmlCursor temp = cursor.Clone();
                    temp.StartPos.SetPos(cursor.EndPos.ActualNode, XmlCursorPositions.CursorInFrontOfNode);
                    await DeleteSelection(temp);

                    // delete the start node, or a part of it
                    // -> Done by recursion in the selection delete method
                    cursor.EndPos.SetPos(cursor.StartPos.ActualNode, XmlCursorPositions.CursorBehindTheNode);
                    return(await DeleteSelection(cursor));
                }
            }
        }
예제 #10
0
        protected override async Task <PaintContext> PaintInternal(PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, IGraphics gfx, PaintModes paintMode, int depth)
        {
            paintContext.PaintPosX += 3;

            var actualText      = ToolboxXml.TextFromNodeCleaned(XmlNode);
            var selection       = this.CalculateStartAndEndOfSelection(actualText, cursor);
            var actualPaintData = LastPaintingDataText.CalculateActualPaintData(paintContext, cursorBlinkOn, this.XmlNode, actualText, this.Config.FontTextNode.Height, cursor, selection.Start, selection.Length);

            var alreadyUnpainted = false;

            switch (paintMode)
            {
            case PaintModes.ForcePaintNoUnPaintNeeded:
                alreadyUnpainted   = true;
                this.lastPaintData = null;
                break;

            case PaintModes.ForcePaintAndUnpaintBefore:
                alreadyUnpainted   = true;
                this.lastPaintData = null;
                this.UnPaint(gfx);
                break;

            case PaintModes.OnlyPaintWhenChanged:
                if (!actualPaintData.Equals(lastPaintData))
                {
                    this.lastPaintData = null;
                }
                break;
            }

            if (this.lastPaintData != null && this.lastPaintContextResult != null)
            {
                return(lastPaintContextResult.Clone());
            }

            this.lastPaintData  = actualPaintData;
            this.cursorPaintPos = null;

            if (lastFontHeight != this.Config.FontTextNode.Height)
            {
                lastFontHeight          = this.Config.FontTextNode.Height;
                lastCalculatedFontWidth = await this.xmlEditor.NativePlatform.Gfx.MeasureDisplayStringWidthAsync("W", this.Config.FontTextNode);
            }

            paintContext.HeightActualRow = Math.Max(paintContext.HeightActualRow, this.Config.MinLineHeight);

            int marginY = (paintContext.HeightActualRow - this.Config.FontTextNode.Height) / 2;

            const int charMarginRight = 2;

            var textPartsRaw = TextSplitHelper.SplitText(
                text: actualText,
                invertStart: selection.Start,
                invertLength: selection.Length,
                maxLength: (int)((paintContext.LimitRight - paintContext.LimitLeft) / lastCalculatedFontWidth) - charMarginRight,
                maxLengthFirstLine: (int)((paintContext.LimitRight - paintContext.PaintPosX) / lastCalculatedFontWidth) - charMarginRight)
                               .ToArray();

            var newTextParts = this.GetTextLinesFromTextParts(textPartsRaw, paintContext, cursorBlinkOn, cursor, lastCalculatedFontWidth).ToArray();

            // Now draw the content, if necessary wrap to several text parts and lines
            for (int i = 0; i < newTextParts.Length; i++)
            {
                var newPart = newTextParts[i];
                var oldPart = (this.textParts != null && i < this.textParts.Length) ? this.textParts[i] : null;
                if (alreadyUnpainted == false && newPart.Equals(oldPart))
                {
                    // no need to paint the text part again
                }
                else
                {
                    // draw the inverted background
                    if (!alreadyUnpainted && oldPart != null)
                    {
                        gfx.UnPaintRectangle(oldPart.Rectangle);
                    }

                    if (newPart.Inverted || this.colorBackground != this.Config.ColorBackground)
                    {
                        gfx.AddJob(new JobDrawRectangle
                        {
                            Batchable = true,
                            Layer     = GfxJob.Layers.TagBackground,
                            Rectangle = newPart.Rectangle,
                            FillColor = newPart.Inverted ? this.colorBackground.InvertedColor : this.colorBackground,
                        });
                    }

                    // draw the text
                    gfx.AddJob(new JobDrawString
                    {
                        Batchable = false,
                        Layer     = GfxJob.Layers.Text,
                        Text      = newPart.Text,
                        Color     = newPart.Inverted ? this.colorText.InvertedColor : this.colorText,
                        X         = newPart.Rectangle.X,
                        Y         = newPart.Rectangle.Y + marginY,
                        Font      = Config.FontTextNode
                    });;
                }
                paintContext.PaintPosY = newPart.Rectangle.Y;
                paintContext.PaintPosX = newPart.Rectangle.X + newPart.Rectangle.Width;
                paintContext.FoundMaxX = Math.Max(paintContext.FoundMaxX, paintContext.PaintPosX);
            }

            if (this.textParts != null) // unpaint old text parts out of new parts range
            {
                for (int i = newTextParts.Length; i < this.textParts.Length; i++)
                {
                    gfx.UnPaintRectangle(this.textParts[i].Rectangle);
                }
            }

            this.textParts = newTextParts;

            paintContext.PaintPosX += 2;

            this.lastPaintContextResult = paintContext.Clone();
            return(paintContext.Clone());
        }
예제 #11
0
        /// <summary>
        /// Draws the XML element on the screen
        /// </summary>
        public async Task <PaintContext> Paint(PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, IGraphics gfx, PaintModes paintMode, int depth)
        {
            if (this.disposed)
            {
                return(paintContext);
            }
            if (this.XmlNode == null)
            {
                return(paintContext);
            }
            if (this.xmlEditor == null)
            {
                return(paintContext);
            }

            paintContext = await PaintInternal(paintContext, cursorBlinkOn, cursor, gfx, paintMode, depth);

            if (this.cursorPaintPos != null && cursorBlinkOn)
            {
                this.PaintCursor(gfx);
            }
            return(paintContext);
        }
예제 #12
0
        private Selection CalculateStartAndEndOfSelection(string actualText, XmlCursor cursor)
        {
            var result = new Selection {
                Start = -1, Length = 0
            };

            if (cursor.StartPos.ActualNode == this.XmlNode) // The start of the selection is on this node
            {
                switch (cursor.StartPos.PosOnNode)
                {
                case XmlCursorPositions.CursorOnNodeStartTag:     // The node itself is selected as start node
                case XmlCursorPositions.CursorOnNodeEndTag:
                    throw new ArgumentOutOfRangeException($"{nameof(cursor.StartPos.PosOnNode)}:{cursor.StartPos.PosOnNode.ToString()} not possible on a text node");
                // result.Start = 0;
                // result.Length = actualText.Length;
                // break;

                case XmlCursorPositions.CursorBehindTheNode:
                case XmlCursorPositions.CursorInsideTheEmptyNode:
                    // Since the cursor position arrives sorted, the EndPos can only lie behind the node
                    result.Start  = -1;
                    result.Length = 0;
                    break;

                case XmlCursorPositions.CursorInFrontOfNode:
                case XmlCursorPositions.CursorInsideTextNode:

                    if (cursor.StartPos.PosOnNode == XmlCursorPositions.CursorInsideTextNode)
                    {
                        result.Start = Math.Max(0, cursor.StartPos.PosInTextNode);     // inside text node
                    }
                    else
                    {
                        result.Start = 0;     // in front of the node
                    }

                    if (cursor.EndPos.ActualNode == this.XmlNode)     // If the end of the selection also is inside this node
                    {
                        switch (cursor.EndPos.PosOnNode)
                        {
                        case XmlCursorPositions.CursorOnNodeStartTag:         // start node is in front of the node, end node behind: everything is selected
                        case XmlCursorPositions.CursorOnNodeEndTag:
                        case XmlCursorPositions.CursorBehindTheNode:
                            result.Length = Math.Max(0, actualText.Length - result.Start);
                            break;

                        case XmlCursorPositions.CursorInsideTheEmptyNode:
                            result.Start  = -1;
                            result.Length = 0;
                            break;

                        case XmlCursorPositions.CursorInsideTextNode:          // till the marker in the text
                            result.Length = Math.Max(0, cursor.EndPos.PosInTextNode - result.Start);
                            break;

                        case XmlCursorPositions.CursorInFrontOfNode:
                            result.Length = 0;
                            break;

                        default:
                            throw new ApplicationException("unknown cursor.EndPos.PosOnNode '" + cursor.EndPos.PosOnNode + "'B");
                        }
                    }
                    else                                                                                  // The end of the selection is not inside this node
                    {
                        if (cursor.EndPos.ActualNode.ParentNode == cursor.StartPos.ActualNode.ParentNode) // If start and end are different, but directly in the same parent
                        {
                            result.Length = Math.Max(0, actualText.Length - result.Start);                // Select only the selected part
                        }
                        else                                                                              // Start and end are different and have different parents
                        {
                            result.Start  = 0;
                            result.Length = actualText.Length;       // select whole text node
                        }
                    }
                    break;

                default:
                    throw new ApplicationException("unknown cursor.StartPos.PosOnNode '" + cursor.StartPos.PosOnNode + "'A");
                }
            }
            else // The start of the selection is not on this node
            {
                if (cursor.EndPos.ActualNode == this.XmlNode) // But the end of the selection is
                {
                    switch (cursor.EndPos.PosOnNode)
                    {
                    case XmlCursorPositions.CursorOnNodeStartTag:       // The node itself is selected as End-Node
                    case XmlCursorPositions.CursorOnNodeEndTag:         // start node is in front of the node, end node behind: everything is selected
                    case XmlCursorPositions.CursorBehindTheNode:
                        result.Start  = 0;
                        result.Length = actualText.Length;
                        break;

                    case XmlCursorPositions.CursorInsideTheEmptyNode:
                        result.Start  = -1;
                        result.Length = 0;
                        break;

                    case XmlCursorPositions.CursorInsideTextNode:                                         // Start node is in front of the node, end node in the middle, so select from front to middle
                        if (cursor.EndPos.ActualNode.ParentNode == cursor.StartPos.ActualNode.ParentNode) // If start and end are different, but directly in the same parent
                        {
                            result.Start  = 0;
                            result.Length = Math.Max(0, cursor.EndPos.PosInTextNode); // Select only the selected front part
                        }
                        else                                                          // Start and end different and different parents
                        {
                            result.Start  = 0;
                            result.Length = actualText.Length;       // select whole text node
                        }
                        break;

                    case XmlCursorPositions.CursorInFrontOfNode:     // Start node is in front of the node, end node also
                        result.Start  = -1;
                        result.Length = 0;
                        break;

                    default:
                        throw new ApplicationException("unknown cursor.EndPos.PosOnNode '" + cursor.EndPos.PosOnNode + "'X");
                    }
                }
                else // Neither the start nor the end of the selection lies exactly on this node
                {
                    if (XmlCursorSelectionHelper.IsThisNodeInsideSelection(EditorState.CursorOptimized, this.XmlNode))
                    {
                        result.Start  = 0;
                        result.Length = actualText.Length;   // Select entire text node
                    }
                }
            }
            return(result);
        }
예제 #13
0
        private IEnumerable <TextPart> GetTextLinesFromTextParts(TextSplitHelper.TextPartRaw[] parts, PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, double fontWidth)
        {
            paintContext.HeightActualRow = Math.Max(paintContext.HeightActualRow, this.Config.MinLineHeight);
            var x                      = paintContext.PaintPosX;
            var y                      = paintContext.PaintPosY;
            var actualLine             = 0;
            var actualTextPartStartPos = 0;

            foreach (var part in parts)
            {
                var newLine = part.LineNo != actualLine;
                if (newLine)
                {
                    actualLine = part.LineNo;
                    y         += paintContext.HeightActualRow;
                    x          = paintContext.LimitLeft;
                }
                var width    = (int)(part.Text.Length * fontWidth);
                var textPart = new TextPart
                {
                    Text        = part.Text,
                    Inverted    = part.Inverted,
                    Rectangle   = new Rectangle(x, y, width, paintContext.HeightActualRow),
                    CursorPos   = -1,
                    CursorBlink = cursorBlinkOn,
                };

                if (this.XmlNode == cursor.StartPos.ActualNode) // is the cursor inside the current text node
                {
                    // Check if the cursor is within this text part
                    var cursorPos = -1;
                    if (cursor.StartPos.ActualNode == this.XmlNode && !cursor.IsSomethingSelected)
                    {
                        switch (cursor.StartPos.PosOnNode)
                        {
                        case XmlCursorPositions.CursorInFrontOfNode:
                            if (part == parts.First())
                            {
                                cursorPos = 0;
                            }
                            break;

                        case XmlCursorPositions.CursorBehindTheNode:
                            if (part == parts.Last())
                            {
                                cursorPos = part.Text.Length;
                            }
                            break;

                        case XmlCursorPositions.CursorInsideTextNode:
                            if ((cursor.StartPos.PosInTextNode >= actualTextPartStartPos) && (cursor.StartPos.PosInTextNode <= actualTextPartStartPos + part.Text.Length))
                            {
                                cursorPos = (int)(cursor.StartPos.PosInTextNode - actualTextPartStartPos);
                            }
                            break;
                        }
                    }
                    if (cursorPos != -1)
                    {
                        textPart.CursorPos  = cursorPos;
                        this.cursorPaintPos = new Point(
                            textPart.Rectangle.X + (int)(textPart.CursorPos * lastCalculatedFontWidth),
                            textPart.Rectangle.Y
                            );
                    }
                }

                x += 1 + width;
                yield return(textPart);

                actualTextPartStartPos += part.Text.Length;
            }
        }
예제 #14
0
        protected override async Task <PaintContext> PaintInternal(PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, IGraphics gfx, PaintModes paintMode, int depth)
        {
            this.nodeDimensions.Update();
            var isSelected = cursor?.StartPos != null && cursor?.EndPos != null && XmlCursorSelectionHelper.IsThisNodeInsideSelection(cursor, this.XmlNode);

            this.CreateChildElementsIfNeeded(gfx);

            Point newCursorPaintPos = null;

            bool alreadyUnpainted = false;

            switch (paintMode)
            {
            case PaintModes.ForcePaintNoUnPaintNeeded:
                alreadyUnpainted = true;
                break;

            case PaintModes.ForcePaintAndUnpaintBefore:
                this.UnPaint(gfx);
                alreadyUnpainted = true;
                break;

            case PaintModes.OnlyPaintWhenChanged:
                break;
            }

            // If the cursor is inside the empty node, then draw the cursor there
            if (cursor.StartPos.ActualNode == this.XmlNode)
            {
                if (cursor.StartPos.PosOnNode == XmlCursorPositions.CursorInFrontOfNode)
                {
                    // remember position for cursor line
                    newCursorPaintPos = new Point(paintContext.PaintPosX, paintContext.PaintPosY);
                }
            }

            var cursorIsOnThisNode = cursor.StartPos.ActualNode == this.XmlNode || cursor.EndPos.ActualNode == this.XmlNode;

            paintContext = await this.startTag.Paint(paintContext, cursorIsOnThisNode, cursorBlinkOn, alreadyUnpainted, isSelected, gfx);

            // If the cursor is inside the empty node, then draw the cursor there
            if (cursor.StartPos.ActualNode == this.XmlNode)
            {
                if (cursor.StartPos.PosOnNode == XmlCursorPositions.CursorInsideTheEmptyNode)
                {
                    // set position for cursor line
                    newCursorPaintPos = new Point(paintContext.PaintPosX - 1, paintContext.PaintPosY);
                }
            }

            paintContext = await this.PaintSubNodes(paintContext, cursorBlinkOn, cursor, gfx, paintMode, depth);

            if (this.endTag != null)
            {
                paintContext = await this.endTag.Paint(paintContext, cursorIsOnThisNode, cursorBlinkOn, alreadyUnpainted, isSelected, gfx);
            }

            // If the cursor is behind the node, then also draw the cursor there
            if (cursor.StartPos.ActualNode == this.XmlNode)
            {
                if (cursor.StartPos.PosOnNode == XmlCursorPositions.CursorBehindTheNode)
                {
                    newCursorPaintPos = new Point(paintContext.PaintPosX - 1, paintContext.PaintPosY);
                }
            }

            this.cursorPaintPos = newCursorPaintPos;
            return(paintContext.Clone());
        }
예제 #15
0
        protected async Task <PaintContext> PaintSubNodes(PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, IGraphics gfx, PaintModes paintMode, int depth)
        {
            if (this.XmlNode == null)
            {
                throw new ApplicationException("PaintSubNodes:xmlNode is null");
            }

            var childPaintContext = paintContext.Clone();

            childPaintContext.LimitLeft = paintContext.LimitLeft + this.Config.ChildIndentX;

            for (int childLauf = 0; childLauf < this.XmlNode.ChildNodes.Count; childLauf++)
            {
                // At this point, the ChildControl object should contain the corresponding instance of the XMLElement control for the current XMLChildNode
                var childElement = (XmlElement)childElements[childLauf];
                var displayType  = this.XmlRules.DisplayType(childElement.XmlNode);
                switch (displayType)
                {
                case DisplayTypes.OwnRow:

                    // This child element starts a new row and is then drawn in this row

                    // start new row
                    childPaintContext.LimitLeft       = paintContext.LimitLeft + this.Config.ChildIndentX;
                    childPaintContext.PaintPosX       = childPaintContext.LimitLeft;
                    childPaintContext.PaintPosY      += this.Config.SpaceYBetweenLines + paintContext.HeightActualRow; // line break
                    childPaintContext.HeightActualRow = 0;                                                             // no element in this line yet, therefore Height 0
                                                                                                                       // Set X-cursor to the start of the new line
                                                                                                                       // line down and then right into the ChildElement
                                                                                                                       // Line down
                    bool paintLines = false;
                    if (paintLines)
                    {
                        gfx.AddJob(new JobDrawLine
                        {
                            Layer     = GfxJob.Layers.TagBorder,
                            Batchable = true,
                            Color     = Color.LightGray,
                            X1        = paintContext.LimitLeft,
                            Y1        = paintContext.PaintPosY + this.Config.MinLineHeight / 2,
                            X2        = paintContext.LimitLeft,
                            Y2        = childPaintContext.PaintPosY + this.Config.MinLineHeight / 2
                        });

                        // Line to the right with arrow on ChildElement
                        gfx.AddJob(new JobDrawLine
                        {
                            Layer     = GfxJob.Layers.TagBorder,
                            Batchable = true,
                            Color     = Color.LightGray,
                            X1        = paintContext.LimitLeft,
                            Y1        = childPaintContext.PaintPosY + this.Config.MinLineHeight / 2,
                            X2        = childPaintContext.LimitLeft,
                            Y2        = childPaintContext.PaintPosY + this.Config.MinLineHeight / 2
                        });
                    }

                    childPaintContext = await childElement.Paint(childPaintContext, cursorBlinkOn, cursor, gfx, paintMode, depth + 1);

                    break;

                case DisplayTypes.FloatingElement:
                    // This child is a floating element; it inserts itself into the same line as the previous element and does not start a new line unless the current line is already too long
                    if (childPaintContext.PaintPosX > paintContext.LimitRight)     //  If the row is already too long
                    {
                        // to next row
                        paintContext.PaintPosY      += paintContext.HeightActualRow + this.Config.SpaceYBetweenLines;
                        paintContext.HeightActualRow = 0;
                        paintContext.PaintPosX       = paintContext.RowStartX;
                    }
                    else     // fits into this line
                    {
                        // set the child to the right of it
                    }
                    childPaintContext = await childElement.Paint(childPaintContext, cursorBlinkOn, cursor, gfx, paintMode, depth + 1);

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(displayType) + ":" + displayType.ToString());
                }
                paintContext.FoundMaxX = childPaintContext.FoundMaxX;
                paintContext.PaintPosX = childPaintContext.PaintPosX;
                paintContext.PaintPosY = childPaintContext.PaintPosY;
            }

            // If we have more ChildControls than XMLChildNodes, then delete them at the end of the ChildControl list
            while (this.XmlNode.ChildNodes.Count < childElements.Count)
            {
                var deleteChildElement = childElements[childElements.Count - 1];
                deleteChildElement.UnPaint(gfx);
                childElements.Remove(childElements[childElements.Count - 1]);
                deleteChildElement.Dispose();
            }
            return(paintContext);
        }
 public static LastPaintingDataText CalculateActualPaintData(PaintContext paintContext, bool cursorBlinkOn, XmlNode node, string actualText, int fontHeight, XmlCursor cursor, int selectionStart, int selectionLength)
 {
     return(new LastPaintingDataText
     {
         LastCursor = cursor.Clone(),
         LastPaintPosY = paintContext.PaintPosY,
         LastPaintPosX = paintContext.PaintPosX,
         LastPaintLimitRight = paintContext.LimitRight,
         LastPaintContent = actualText,
         LastPaintTextFontHeight = fontHeight,
         SelectionStart = selectionStart,
         SelectionLength = selectionLength,
         CursorInNode = cursor.StartPos.ActualNode == node,
         CursorPosInNode = cursor.StartPos.PosInTextNode,
         CursorBlinkOn = cursorBlinkOn,
         LastCursorPos = cursor.StartPos.PosOnNode,
     });
 }