Nevron Open Vision Documentation
Painting

 
Painting Overview

The DOM paints itself by using an instance of the NPaintVisitor class. The NPaintVisitor class derives from the NDisplayVisitor class, and inherits the transform and clip management provided by it, as explained in the The Visual Tree topic.

During the pre-visiting step, the paint visitor indirectly calls the OnPrePaint protected virtual method of NVisual. This method should be overriden in descendant classes, that need to paint content that appears under the content rendered by descendant visuals.

During the post-visiting step, the paint visitor indirectly calls the OnPostPaint protected virtual method of NVisual. This method should be overriden in descendant classes, that need to paint content that appears above the content rendered by descendant visuals.

Prior to calling the OnPrePaint and OnPostPaint methods, the paint visitor has already consumed the local transform and clip that the visual may provide, so the painting is performed in local coordinates and with an already applied clip. Both the OnPrePaint and OnPostPaint method receive as argument the NPaintVisitor instance, that currently paints the visual.

The rest of the topic discusses the API available for high level painting with a paint visitor.

Painting with a NPaintVisitor

The methods that the NPaintVisitor provides, that are related to painting are separated into two distinct groups - styling and geometry/text. The styling methods let you specify the current fill, stroke, shadow and font, that are used to paint the subsequently rendered geometries/texts. The separation between styling and geometry/text allows for multiple geometries and text to be rendered with a single styling configuration.

Typically the start of a new style configuration is marked with a call to the ClearStyles() method, that clears all possible styles from a paint visitor. The following code sample renders a red rectangle with a solid black outline, that is 2 dips wide:

Painting a rectangle
Copy Code
protected override void OnPrePaint(NPaintVisitor visitor)
{
    base.OnPrePaint(visitor);
    visitor.ClearStyles();
    visitor.SetFill(NColor.Red);
    visitor.SetStroke(NColor.Black, 2.0d);
    visitor.PaintRectangle(new NRectangle(10, 10, 100, 100));           
}

The following table outlines the NPaintVisitor methods that alter the respective paint styles:

Method Description

Fill

void SetFill(NFill fill)

Sets the current fill to the specified NFill instance. A value of null clears the fill.

void SetFill(NColor color)

Sets the current fill to a solid color fill.

void SetFill(ENGradientStyle gradStyle, ENGradientVariant gradVar, NColor beginColor, NColor endColor)

Sets the current fill to a stock gradient fill with the specified settings.

void SetFill(ENHatchStyle hatchStyle, NColor foreColor, NColor backColor)

Sets the current fill to a hatch fill with the specified settings.

void SetFill(NImageSource imageSource, NTextureMapping textureMapping)

Sets the current fill to an image fill with the specified settings.

void ClearFill()

Clears the current fill. Subsequent geometries and text will not be filled.

Stroke

void SetStroke(NStroke stroke)

Sets the current stroke to the specified NStroke instance. A value of null clears the stroke.

void SetStroke(NColor color, double width)

Sets the current stroke to be a solid stroke with the specified color and width.

void ClearStroke()

Clears the current stroke. Subsequent geometries and text will not be stroked.

Font

void SetFont(NFont font)

Sets the current font the specified NFont instance. A value of null clears the font.

void ClearFont()

Clears the current font. Subsequent texts will not be rendered.

Shadow

void SetShadow(NShadow shadow)

Sets the current shadow to the specified NShadow instance. A value of null clears the shadow.

void ClearShadow()

Clears the shadow style. Subsequent geometry/text commands will not drop a shadow.

The following table outlines the NPaintVisitor methods that paint geometries and strings:

Method Description Uses Fill Uses Stroke Uses Shadow Uses Font

Filled and Stroked Geometries

void PaintRectangle(NRectangle rect)

Paints a rectangle X X X

void PaintQuadrangle(NQuadrangle quad, ENFillRule fillRule)

Paints a quadrangle X X X

void PaintTriangle(NTriangle triangle)

Paints a triangle X X X

void PaintEllipse(NRectangle rect)

Paints an ellipse X X X

void PaintPolygon(NPolygon polygon, ENFillRule fillRule)

Paints a polygon X X X

void PaintEllipse(NRectangle rect)

Paints an ellipse X X X

void PaintPath(NGraphicsPath path, ENFillRule fillRule)

Paints a path X X X

Stroked Geometries

void PaintLine(NPoint start, NPoint end)

Paints a line X X

void PaintPolyline(NPolyline polyline)

Paints a polyline X X

String Painting

void PaintString(NPoint location, string text, ref NPaintTextPointSettings settings)

Paints a string at location X X X X

void PaintString(NRectangle rect, string text, ref NPaintTextRectSettings settings)

Paints a string in rectangle X X X X

Image Painting

void PaintImage(NImageSource imageSource, NPoint location)

Paints an image at location

void PaintImage(NImageSource imageSource, NRectangle bounds)

Paints an image in rectangle

Repainting and Meta Markup

We have already seen that the painting of the visual tree is performed by an instance of the NPaintVisitor that "visits" the visuals and asks them to paint themselves. However, when visuals needs to be rendered on screen the repainting of the entire window visuals tree can be quite a complex task. In order to optimize the repaint of visuals that reside in windows, the DOM implements a complex display validation algorithm that is automatically performed

The DOM handles the repaint of the visual trees that reside in windows automatically. It is however up to the develop to inform the DOM that a certain visual needs to be repainted. This is achieved by calling the NVisual-InvalidateDisplay() method. By invalidating the display of the visual, you inform the DOM that the respective visual needs to be repainted on the next window frame.

You need to call the NVisual-InvalidateDisplay() method when there is a chance that the painting code that you have written in the OnPrePaint and OnPostPaint overrides can produce different visual results. Typically in the OnPrePaint and OnPostPaint overrides you will render styles, geometries and text that are exposed by properties of your visual. Such properties can be marked as "affecting the display" of the visual. The DOM will automatically call the NVisual-InvalidateDisplay() method, when the value of these properties changes. To illustrate the approach lets elaborate the paint rectangle example:

My First Visual
Copy Code
public class MyFirstVisual : NVisual
{
 public MyFirstVisual() { }
 static MyFirstVisual() 
 {
  MyFirstVisualSchema = NSchema.Create(typeof(MyFirstVisual), NVisual.NVisualSchema);
  // add the properties
  // note that they are marked as affecting the display of the visual
  RectangleProperty = MyFirstVisualSchema.AddSlot("Rectangle", NDomType.NRectangle, NRectangle.Zero);
  RectangleProperty.SetAffectsDisplay(true);
 
  FillProperty = MyFirstVisualSchema.AddSlot("Fill", typeof(NFill), null);
  FillProperty.SetAffectsDisplay(true);
  StrokeProperty = MyFirstVisualSchema.AddSlot("Stroke", typeof(NStroke), null);
  StrokeProperty.SetAffectsDisplay(true);
 }
 public NRectangle Rectangle { get { return (NRectangle)GetValue(RectangleProperty); } set { SetValue(RectangleProperty, value); } }
 public NFill Fill { get { return (NFill)GetValue(FillProperty); } set { SetValue(FillProperty, value); } }
 public NStroke Stroke { get { return (NStroke)GetValue(StrokeProperty); } set { SetValue(StrokeProperty, value); } }
 protected override void OnPrePaint(NPaintVisitor visitor)
 {
  base.OnPrePaint(visitor);
  // consume the properties values to render a rectangle 
  // note that the properties are marked as affecting the display of the visual
  visitor.ClearStyles();
  visitor.SetFill(Fill);
  visitor.SetStroke(Stroke);
  visitor.PaintRectangle(Rectangle);
 }
 public static readonly NSchema MyFirstVisualSchema;
 public static readonly NProperty RectangleProperty;
 public static readonly NProperty FillProperty;
 public static readonly NProperty StrokeProperty;
}

As seen in the example, the properties of the MyFirstVisual are marked as affecting its display, because they participate in the visual painting. The DOM will automatically repaint the visual when these properties change (the property metadata is discussed in the Properties topic).

When visuals enter and leave a document, they are automatically pooled for display validation, so no special markup is needed to repaint the visual, if it delegates the painting to other visuals. There are cases however when the visual contains elements, that are not visuals, but which still participate in its rendering. In such cases you can use the NSchema-SetChildrenAffectDisplay method to inform the DOM to invalidate the visual display, whenever the set of child elements of the visual changes. Similarly properties of non-visual elements can be marked as affecting the parent display via the NProperty-SetAffectsParentDisplay method.

See Also
Send Feedback