/// <summary> /// Draws the vertical cursor line /// </summary> protected virtual void PaintCursor(IGraphics gfx) { if (this.cursorPaintPos == null) { return; } if (this.EditorState.CursorBlink.PaintCursor == false) { return; } var height = (int)(Math.Max(this.editorContext.EditorConfig.FontTextNode.Height, this.editorContext.EditorConfig.FontNodeName.Height) * 1.6); var margin = height / 5; gfx.AddJob(new JobDrawLine { Batchable = true, Layer = GfxJob.Layers.Cursor, Color = Color.Black, LineWidth = 2, X1 = cursorPaintPos.X, Y1 = cursorPaintPos.Y + margin, X2 = cursorPaintPos.X, Y2 = cursorPaintPos.Y + height - margin }); }
internal static void DrawNodeBodyByCoordinates(GfxJob.Layers layer, int x1, int y1, int x2, int y2, int cornerRadius, Color fillColor, Color borderColor, IGraphics gfx) { gfx.AddJob(new JobDrawPolygon { Batchable = true, Layer = layer, FillColor = fillColor == Color.Transparent ? null : fillColor, BorderColor = borderColor == Color.Transparent ? null : borderColor, BorderWidth = 1, Points = new[] { new Point(x1 + cornerRadius, y1), new Point(x2 - cornerRadius, y1), new Point(x2, y1 + cornerRadius), new Point(x2, y2 - cornerRadius), new Point(x2 - cornerRadius, y2), new Point(x1 + cornerRadius, y2), new Point(x1, y2 - cornerRadius), new Point(x1, y1 + cornerRadius) } }); }
/// <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, 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()); }
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); }
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); }