libShiva

Example: Stroke, fill and gradients

Every libShiva path has its stroke and fill properties. These define how the outline of the path will look like and what fill will be used in case the path is closed. Strokes and fills can have solid color, use alpha channel for transparency or use linear/radial gradients.

Solid color

There are multiple variations of setStroke() and setFill functions defined. The simplest of them take arguments for each of the R,G,B,A colors. In case the A parameter is ommited, its default value of 255 is taken, which means fully opaque color. Lets create a rectangle with a red outline and a half-transparent green fill.

  RectangleRef rc = new Rectangle(100,100,200,200);
  rc->setStroke(255,0,0);
  rc->setFill(0,255,0,128);

Instead of passing each color as a parameter you can construct a Color object and pass it to the style functions:

  Color cs(255,0,0);
  Color cf(0,255,0,128);
  rc->setStroke(cs);
  rc->setFill(cf);

To toggle whether the stroke or fill is used or not once its color has been set we use two specific functions - setIsStroked() and setIsFilled() - passing them a boolean value. Note that any subsequent call to setStroke or setFill will automatically enable the use of stroke and/or fill again. The following code:

  rc->setIsStroked(false);
  rc->setStroke(255,0,0);
  rc->setIsFilled(false);

... would result in a rectangle with a red outline and no fill.


Stroke styles

Apart from the color we can set two additional parameters of the stroke: its width and cap. Obviously width defines how wide in pixels will the outline of a shape be. To set it we call the setStrokeWidth() function on any Path. On the other hand, cap defines how the endings of the line will look like, when the path is not closed. To make the endings round we pass the CAP_ROUND flag as the argument to the setStrokeCap() function. To make them flat (rectangular) we use the CAP_BUTT flag instead. Any stroke defaults to a flat cap.

  LineRef ln1 = new Line(100,100,200,200);
  ln1->setStroke(0,160,0);
  ln1->setStrokeWidth(5);

  LineRef ln2 = new Line(200,200,100,100);
  ln2->setStroke(255,0,255);
  ln2->setStrokeWidth(10);
  ln2->setStrokeCap(CAP_ROUND);


Gradients

libShiva currently supports two types of gradients: linear and radial. Each of them has its own class in the API: LinearGradient and RadialGradient respectively. To construct a gradient we must first specify the way how it is going to be placed relative to the shape.

The LinearGradient constructor takes the X and Y coordinates of the start and end points as the first 4 arguments. The last argument is the unit-space which these coordinates are defined in. The values available for the unit-space are UNIT_SPACE_GLOBAL and UNIT_SPACE_BOUNDBOX. The former means that the start and end points of the gradient are given in the global space and not relative to the target shape. The latter means that the start and end points coordinates are relative to the targets bounding-box, thus (0,0) being the top-left corner of the bounding-box and (1,1) being its bottom-right corner.

Lets see how to construct a linear gradient crossing the target shape diagonally from its top-left to its bottom-right side:

  LinearGradientRef lgrad =
    new LinearGradient(0,0,1,1,UNIT_SPACE_BOUNDBOX);

A radial gradient takes the X and Y coordinates of its center and the radius size in pixels as the first 3 arguments of its constructor. The last argument is the unit-space used for those coordinates again. In case the unit-space is relative to bounding-box, the radius of 1 would actually mean that the X radius is equal to the width of the bounding-box and Y radius is equal to the height of the bounding-box.

The following code creates a radial gradient which is centered to the target shape and has the radius if its inscribed circle or ellipse (in case the bounding-box is not square):

  RadialGradientRef rgrad =
    new RadialGradient(0.5,0.5,0.5,UNIT_SPACE_BOUNDBOX);

To set the colors of a gradient we add the so-called stops to it. Each stop describes a color node at a certain offset along the direction in which the gradient expands. When a gradient is drawn the colors get interpolated in-between these color nodes.

We specify a gradient stop by giving its offset and its color. The color value can either be a series of 4 RGBA arguments (3 arguments for A defaulting to 255) or a Color object.

Here we add two stops to our linear gradient, first being green at the offset of 0 and the second being half-transparent purple at the offset of 1:

  lgrad->addStop(0, 0,160,0);
  lgrad->addStop(1, 0,255,255, 128);

Gradients are applied to shapes just like the solid colors are - by passing them as an argument to the setStroke() or setFill functions:

  ln->setStroke(lgrad);
  rc->setFill(rgrad);