/// <summary>
        /// Draws the attributes
        /// </summary>
        private async Task <PaintContext> PaintAttributes(PaintContext paintContext, string attributesString, bool isSelected, IGraphics gfx)
        {
            paintContext = paintContext.Clone();

            if (string.IsNullOrWhiteSpace(attributesString))
            {
                return(paintContext);
            }

            var attributeWidth = await this.GetAttributeTextWidth(attributesString, gfx);

            // draw a frame around the attributes
            StandardNodeTagPaint.DrawNodeBodyBySize(GfxJob.Layers.AttributeBackground,
                                                    paintContext.PaintPosX, paintContext.PaintPosY + this.dimensions.AttributeMarginY,
                                                    attributeWidth, this.dimensions.AttributeHeight, 2,
                                                    isSelected ? this.config.ColorNodeAttributeBackground.InvertedColor : this.config.ColorNodeAttributeBackground,
                                                    isSelected ? this.config.ColorNodeTagBorder.InvertedColor : this.config.ColorNodeTagBorder,
                                                    gfx);

            // Draw attributes
            gfx.AddJob(new JobDrawString
            {
                Batchable = false,
                Layer     = GfxJob.Layers.Text,
                Text      = attributesString.ToString(),
                Color     = isSelected ? this.config.ColorText.InvertedColor : this.config.ColorText,
                X         = paintContext.PaintPosX,
                Y         = paintContext.PaintPosY + this.dimensions.AttributeMarginY + this.dimensions.AttributeInnerMarginY + 1,
                Font      = config.FontNodeAttribute
            });

            // Set character cursor behind the attributes
            paintContext.PaintPosX += attributeWidth + this.dimensions.InnerMarginX;

            return(paintContext);
        }
        protected override async Task <PaintContext> PaintInternal(PaintContext paintContext, string attributesString, bool isSelected, IGraphics gfx)
        {
            var esteemedWidth = this.nodeNameTextWidth + this.dimensions.InnerMarginX * 3;

            if (paintContext.PaintPosX + esteemedWidth > paintContext.LimitRight)
            {
                paintContext.HeightActualRow = Math.Max(paintContext.HeightActualRow, config.MinLineHeight);
                paintContext.PaintPosX       = paintContext.LimitLeft + this.config.ChildIndentX;
                paintContext.PaintPosY      += paintContext.HeightActualRow;
                paintContext.HeightActualRow = config.MinLineHeight;
            }

            var startX = paintContext.PaintPosX;
            var startY = paintContext.PaintPosY;

            paintContext.PaintPosX += this.dimensions.InnerMarginX;  // margin to left border

            // draw node name
            gfx.AddJob(new JobDrawString
            {
                Batchable = false,
                Layer     = GfxJob.Layers.Text,
                Text      = this.node.Name,
                Color     = isSelected ? this.config.ColorText.InvertedColor : this.config.ColorText,
                X         = paintContext.PaintPosX,
                Y         = paintContext.PaintPosY + this.config.InnerMarginY,
                Font      = this.config.FontNodeName
            });

            paintContext.PaintPosX += nodeNameTextWidth + this.dimensions.InnerMarginX;

            // draw the attributes
            paintContext = await this.PaintAttributes(paintContext, attributesString, isSelected, gfx);

            // standard distance + one pixel to the right, otherwise we draw on the frame line
            paintContext.PaintPosX += 1;

            var borderWidth = paintContext.PaintPosX - startX;

            StandardNodeTagPaint.DrawNodeBodyBySize(
                GfxJob.Layers.TagBackground,
                startX, paintContext.PaintPosY,
                borderWidth, this.config.TagHeight,
                this.dimensions.CornerRadius,
                isSelected ? this.dimensions.BackgroundColor.InvertedColor : this.dimensions.BackgroundColor,
                isSelected ? this.config.ColorNodeTagBorder.InvertedColor : this.config.ColorNodeTagBorder,
                gfx);

            // if necessary draw the continuing arrow at the end of the frame
            if (this.isClosingTagVisible)
            {
                var point1 = new Point(paintContext.PaintPosX, paintContext.PaintPosY + this.config.InnerMarginY);
                var point2 = new Point(paintContext.PaintPosX + this.dimensions.InnerMarginX, paintContext.PaintPosY + this.config.TagHeight / 2);
                var point3 = new Point(paintContext.PaintPosX, paintContext.PaintPosY + this.config.TagHeight - this.config.InnerMarginY);
                gfx.AddJob(new JobDrawPolygon
                {
                    Batchable = true,
                    Layer     = GfxJob.Layers.TagBorder,
                    FillColor = isSelected ? this.config.ColorNodeTagBorder.InvertedColor : this.config.ColorNodeTagBorder,
                    Points    = new[] { point1, point2, point3 }
                });

                // Remember the right arrow area
                this.AreaArrow          = new Rectangle(paintContext.PaintPosX, paintContext.PaintPosY, this.dimensions.InnerMarginX, this.config.TagHeight);
                paintContext.PaintPosX += this.dimensions.InnerMarginX;
            }
            else
            {
                this.AreaArrow = null;
            }

            paintContext.HeightActualRow = System.Math.Max(paintContext.HeightActualRow, this.config.MinLineHeight); // See how high the current line is

            // Remember where the mouse areas are
            this.AreaTag = new Rectangle(startX - 2, startY, paintContext.PaintPosX + 2 - (startX), this.config.TagHeight);

            paintContext.FoundMaxX = System.Math.Max(paintContext.FoundMaxX, paintContext.PaintPosX);

            this.lastPaintContextResult = paintContext.Clone();
            return(paintContext.Clone());
        }
        protected override async Task <PaintContext> PaintInternal(PaintContext paintContext, string attributesString, bool isSelected, IGraphics gfx)
        {
            var startX = paintContext.PaintPosX;

            var esteemedWidth = this.nodeNameTextWidth + this.dimensions.InnerMarginX * 3;

            if (paintContext.PaintPosX + esteemedWidth > paintContext.LimitRight)
            {
                paintContext.HeightActualRow = Math.Max(paintContext.HeightActualRow, config.MinLineHeight);
                paintContext.PaintPosX       = paintContext.LimitLeft + this.config.ChildIndentX;
                paintContext.PaintPosY      += paintContext.HeightActualRow;
                paintContext.HeightActualRow = config.MinLineHeight;
            }

            // draw an arrow to the left in front of the node frame
            // arrow to left
            Point point1 = new Point(paintContext.PaintPosX + this.dimensions.InnerMarginX, paintContext.PaintPosY + this.config.InnerMarginY);
            Point point2 = new Point(paintContext.PaintPosX + this.dimensions.InnerMarginX, paintContext.PaintPosY + this.config.TagHeight - this.config.InnerMarginY);
            Point point3 = new Point(paintContext.PaintPosX, paintContext.PaintPosY + this.config.TagHeight / 2);

            gfx.AddJob(new JobDrawPolygon
            {
                Batchable = true,
                Layer     = GfxJob.Layers.TagBorder,
                FillColor = isSelected ? this.config.ColorNodeTagBorder.InvertedColor : this.config.ColorNodeTagBorder,
                Points    = new[] { point1, point2, point3 }
            });

            // Remember the right arrow area
            this.AreaArrow          = new Rectangle(paintContext.PaintPosX, paintContext.PaintPosY, this.dimensions.InnerMarginX, this.config.TagHeight);
            paintContext.PaintPosX += this.dimensions.InnerMarginX + 1; // Place drawing cursor behind the arrow

            // ## Draw frame for closing node ###
            StandardNodeTagPaint.DrawNodeBodyBySize(GfxJob.Layers.TagBackground,
                                                    paintContext.PaintPosX, paintContext.PaintPosY,
                                                    this.nodeNameTextWidth + this.dimensions.InnerMarginX * 2, this.config.TagHeight, this.dimensions.CornerRadius,
                                                    isSelected ? this.dimensions.BackgroundColor.InvertedColor : this.dimensions.BackgroundColor,
                                                    isSelected ? this.config.ColorNodeTagBorder.InvertedColor : this.config.ColorNodeTagBorder,
                                                    gfx);

            paintContext.PaintPosX += this.dimensions.InnerMarginX; // Distance between frame and font

            //  ## Draw name for closing node ###
            gfx.AddJob(new JobDrawString
            {
                Batchable = false,
                Layer     = GfxJob.Layers.Text,
                Text      = this.node.Name,
                Color     = isSelected ? this.config.ColorText.InvertedColor : this.config.ColorText,
                X         = paintContext.PaintPosX,
                Y         = paintContext.PaintPosY + this.config.InnerMarginY,
                Font      = this.config.FontNodeName
            });

            paintContext.PaintPosX += this.nodeNameTextWidth + this.dimensions.InnerMarginX; // Distance between font and frame

            // One pixel to the right, because otherwise we draw on the frame line and the cursor flashes on the frame
            paintContext.PaintPosX++;

            // Remember where the mouse areas are
            this.AreaTag = new Rectangle(startX, paintContext.PaintPosY, paintContext.PaintPosX - startX, this.config.TagHeight);

            paintContext.FoundMaxX = System.Math.Max(paintContext.FoundMaxX, paintContext.PaintPosX);

            this.lastPaintContextResult = paintContext.Clone();
            await Task.CompletedTask;

            return(paintContext);
        }
Exemple #4
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());
        }
        public async Task <PaintContext> Paint(PaintContext paintContext, bool cursorIsOnThisNode, bool cursorBlinkOn, bool alreadyUnpainted, bool isSelected, IGraphics gfx)
        {
            paintContext.PaintPosX += 1;

            var startX           = paintContext.PaintPosX;
            var startY           = paintContext.PaintPosY;
            var attributesString = this.GetAttributesString();

            if (alreadyUnpainted)
            {
                this.lastPaintContextResult = null;
            }

            if (this.lastTextWidthFontHeight != this.config.FontNodeName.Height)
            {
                this.nodeNameTextWidth       = (int)(await gfx.MeasureDisplayStringWidthAsync(this.node.Name, this.config.FontNodeName));
                this.lastTextWidthFontHeight = this.config.FontNodeName.Height;
                lastPaintContextResult       = null;
            }

            var cursorChanged = false;

            if (cursorIsOnThisNode)
            {
                cursorChanged = cursorBlinkOn != this.lastCursorBlinkOn;
            }
            else
            {
                cursorChanged = cursorIsOnThisNode != this.lastCursorWasOnThisNode;
            }

            if (lastPaintContextResult != null &&
                this.lastPaintX == startX &&
                this.lastPaintY == startY &&
                this.lastPaintWasSelected == isSelected &&
                this.lastAttributeString == attributesString &&
                cursorChanged == false)
            {
                return(lastPaintContextResult.Clone());
            }

            if (!alreadyUnpainted)
            {
                this.Unpaint(gfx);
            }

            this.lastPaintX              = startX;
            this.lastPaintY              = startY;
            this.lastPaintWasSelected    = isSelected;
            this.lastAttributeString     = attributesString;
            this.lastCursorBlinkOn       = cursorBlinkOn;
            this.lastCursorWasOnThisNode = cursorIsOnThisNode;

            paintContext = await this.PaintInternal(paintContext, attributesString, isSelected, gfx);

            paintContext.HeightActualRow = Math.Max(paintContext.HeightActualRow, this.config.MinLineHeight); // See how high the current line is
            paintContext.FoundMaxX       = Math.Max(paintContext.FoundMaxX, paintContext.PaintPosX);

            this.lastPaintContextResult = paintContext.Clone();
            return(paintContext.Clone());
        }