1
votes

I'm trying to port some code from Delphi to Firemonkey (XE6).

I've run into a problem with a function which draws to a TCanvas supplied by the caller. The Canvas could be from a TPaintBox, a TPanel, a TForm or a TBitmap. The function reads the TCanvas.ClipRect property to avoid doing cpu-intensive drawing outside of it. (The cliprect represents invalidated areas of the TForm, TPaintBox etc.)

Unfortunately the TCanvas ClipRect property no longer seems to exist. Does anyone know how I can access the TCanvas.ClipRect in Firemonkey? I did notice that TPaintBox and TPanel now have a ClipRect property, so I could maybe use those, but the TForm and TBitmap don't.

Please note, I'm not trying to create or change a cliprect in a Canvas, I'm trying to read it.

2
You are probably asking the wrong question. The two frameworks are very different. You should ask how to solve the problem in the new framework.David Heffernan
There is no TCanvas.ClipRect, as you can see by examining the FMX.Graphics.pas source code. FMX.Graphics.TCanvas is an abstract class, which means you can't actually create it; you create a descendent of it that implements the functionality and can add other functionality. FMX.Forms.TCustomForm.AddUpdateRects uses TCanvasStyle.SupportClipRects in TCanvasManager.DefaultCanvas.GetCanvasStyle to see if the current canvas even supports ClipRects, which indicates that not all TCanvas descendants do. If the descendent doesn't support it, you can't get it.Ken White
@Ken you can probably go further and say that if the descendant doesn't support it then you don't need it either. :)Deltics
@Ken many thanks for confirming the TCanvas.ClipRect no longer exists.Clover
@David Hefferman You can see in my question I already found a solution in the new framework, by using TPaintBox and TPanel ClipRects. I just wondered if there was a way to still get it from the Canvas which is a more elegant solution. The case of the TForm and TBitmap I'll have to workaround.Clover

2 Answers

1
votes

You use the Scene property of TControl. It has a list of clip rects to be painted. Use GetUpdateRectsCount and GetUpdateRect to read them.

For example this code read out the rects that needs repainting:

  lStr := '';
  for i := 0 to MyControl.Scene.GetUpdateRectsCount-1 do
    with MyControl.Scene.GetUpdateRect(i) do
      lStr := lStr + Format('(%g,%g,%g,%g)', [Left,Top,Right,Bottom]);
0
votes

The DoBeginScene has a parameter for the cliprects. But there doesn't seem to be a way to actually retrieve that value. In addition to that there might be additional clipping on the canvas.

In order to get the clip rects, you need the dc or cgcontext of the canvas. You could get it using RTTI. Here's an example for OSX:

function TCanvasCHelper.GetCGContext: CGContextRef;
var
  Context: TRttiContext;
  Field: TRttiField;
begin
  // needs about 1ms
  Field := Context.GetType(TCanvasQuartz).GetField('FContext');       // get private field using RTTI
  Assert(Field <> nil);
  Result := PPointer(Field.GetValue(Self).GetReferenceToRawData)^;
end;

Unfortunately using RTTI for this might not be as fast as required. I ended up with having to create a copy of the FMX.Canvas.* classes that expose the CGContext or DC. You'll need this anyway if you want to do more advanced things with the canvas that FMX does not implement.

When you have the CGContext or DC, you can use the functions of the OS like CGContextGetClipBoundingBox or GetClipBox to retrieve the cliprects if the canvas supports them.