protected async Task Paint(int limitRight, bool forceRepaint, bool isBecauseOfCursorBlink) { var gfx = this.NativePlatform.Gfx; gfx.DeleteAllPaintJobs(); if (this.EditorState.RootElement == null) { gfx.AddJob(new JobClear()); await gfx.PaintJobs(EditorConfig.ColorBackground); } else { var paintMode = XmlElement.PaintModes.OnlyPaintWhenChanged; if (forceRepaint) { gfx.AddJob(new JobClear()); paintMode = XmlElement.PaintModes.ForcePaintNoUnPaintNeeded; } var paintContext = new PaintContext { LimitLeft = 0, LimitRight = limitRight - 10, PaintPosX = 10, PaintPosY = 10, RowStartX = 10, }; var paintResultContext = await this.EditorState.RootElement.Paint(paintContext.Clone(), EditorState.CursorBlink.PaintCursor, this.EditorState.CursorOptimized, gfx, paintMode, depth : 0); await gfx.PaintJobs(EditorConfig.ColorBackground); const int margin = 20; var newVirtualWidth = ((paintResultContext.FoundMaxX + margin) / margin) * margin; var newVirtualHeight = ((paintResultContext.PaintPosY + margin) / margin) * margin; if (this.VirtualWidth != newVirtualWidth || this.VirtualHeight != newVirtualHeight) { this.VirtualWidth = newVirtualWidth; this.VirtualHeight = newVirtualHeight; await this.VirtualSizeChanged.Trigger(EventArgs.Empty); } } }
/// <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); }
protected abstract Task <PaintContext> PaintInternal(PaintContext paintContext, bool cursorBlinkOn, XmlCursor cursor, IGraphics gfx, PaintModes paintMode, int depth);
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()); }
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); }