Hide Comments
Hide Comments

Writing Cross-Library Code (VCL and FMX Compatible)

Comments (0)

Writing cross-library graphics code (e.g., code that supports both the VCL and FMX versions of the RiverSoftAVG Charting Component Suite) is not easy but it is possible. The RCCS goes to great pains to have generally the exact same interfaces to the RCCS classes whether you use VCL or FMX.

With the judicious use of the RSGraphics unit (or FMX.RS.Graphics unit in FMX) and the FMX.RS.CanvasHelper unit, you should be able to avoid scattering too many IFDEFs throughout your graphics code. The FMX.RS.CanvasHelper unit adds a class helper to the FMX TCanvas, which adds most of the methods of the VCL TCanvas. The RSGraphics/FMX.RS.Graphics unit defines cross-library types, classes, constants, and functions that change based on whether you include the RSGraphics or FMX.RS.Graphics unit. Note you should not include both RSGraphics and FMX.RS.Graphics in the same unit.

The graphics unit defines the following types that change based on whether you are using VCL or FMX:

TCanvasColor = TColor (VCL)/TAlphaColor (FMX)
TTileGraphic = TGraphic (VCL)/TBitmap (FMX)
TRSPen = TPen (VCL)/TRSStroke (FMX)
TRSPicture = TPicture (VCL)/TBitmap (FMX)
TCanvasPixel = Integer (VCL)/Single (FMX)
TCanvasRect = TRect (VCL)/TRectF (FMX)
TCanvasPoint = TPoint (VCL)/TPointF (FMX)
TCanvasPoints = Array of TPoint (VCL)/TPointF (FMX)
TCanvasSize = TSize (VCL)/TSizeF (FMX)
TColors = Array of TColor (VCL)/TAlphaColor (FMX)

It also defines functions that accept and return the correct type for the library based on whether you include RSGraphics or FMX.RS.Graphics. These functions are equivalent to the functions in their respective libraries without the "Canvas" name on front, e.g., CanvasRect(0,0,100,100) acts like Rect(0,0,100,100) in VCL and RectF(0,0,100,100) in FMX. The following functions are defined:

function CanvasRect( Left, Top, Right, Bottom: Integer ): TCanvasRect; inlineoverload;
function CanvasRect( Left, Top, Right, Bottom: Single ): TCanvasRect; inlineoverload;
function CanvasPoint( X, Y: Integer ): TCanvasPoint; inlineoverload;
function CanvasPoint( X, Y: Single ): TCanvasPoint; inlineoverload;
function CanvasRound( X: Single ): TCanvasPixel; inline;
function CanvasTrunc( X: Single ): TCanvasPixel; inline;
function CanvasDiv( X, Y: Integer ): TCanvasPixel; inlineoverload;
function CanvasDiv( X, Y: Single ): TCanvasPixel; inlineoverload;
function CanvasMax( const Data: array of TCanvasPixel ): TCanvasPixel;
function CanvasMin( const Data: array of TCanvasPixel ): TCanvasPixel;
function CanvasCenterPoint( const Rect: TCanvasRect ): TCanvasPoint; inline;

 

Finally, there are color constants defined that map to their equivalents in the VCL or FMX. The color constants start with the "clx" prefix, similar to the "cl" constants in VCL and "cla" constants in FMX. For example, the clxBlue constant equals clBlue when you include RSGraphics and equals claBlue when you include FMX.RS.Graphics.

So, with these functions, types, and constants, you can write code that can be used in either a VCL or FMX application. It is recommended that you write the VCL code first as it is more limited that the FMX library. Note that this example is deliberately contrived to show that there will still be some library dependent code:

{$DEFINE FMX} // should only define in FMX applications only
var
  CenterPt: TCanvasPoint;
  LowerRightQuadrant: TCanvasRect;
begin
  // get center point using cross-library CenterPoint
  CenterPt := CanvasCenterPoint(ARect);
  // create a rectangle using cross-library Rect
  LowerRightQuadrant := CanvasRect(CenterPt.X, CenterPt.Y, ARect.Right, ARect.Bottom);
  // FMX does not have Canvas.Pen property, it is exposed by FMX.RS.CanvasHelper
  // as equivalent to Canvas.Stroke
  // clxCOLORS are from RSGraphics
  Canvas.Pen.Color := clxBlue;
  // FMX does not have Canvas.Brush property, it is exposed in FMX.RS.CanvasHelper
  // as equivalent to Canvas.Fill
  Canvas.Brush.Color := clxRed;
  {$IFDEF FMX}
  Canvas.StrokeDash := TStrokeDash.sdDash; // <--- not cross-library compatible
  {$ELSE}
  Canvas.Pen.Style := psDash; // <--- not cross-library compatible
  {$ENDIF}
  // FMX does not have Canvas.Rectangle method, added in FMX.RS.CanvasHelper
  Canvas.Rectangle(LowerRightQuadrant);
  // Move text down by around a third of width/height of LowerRightQuadrant, use
  // CanvasDiv function from RSGraphics to make the code cross-library
  Canvas.TextOut( CenterPt.X + CanvasDiv(LowerRightQuadrant.Width,3.3), CenterPt.Y + CanvasDiv(LowerRightQuadrant.Height,3.3),
'Hello World' );
end

Comments (0)

RiverSoftAVG Charting Component Suite (RCCS) © 2005-2015, Thomas G. Grubb