iOS7 Blurred Overlay in Delphi XE6
delphi, delphi-xe5, delphi-xe6, firemonkey
Solution
After a little research on how to capture the parent control background I came up with the following code based on TMagnifierGlass class from FMX (Note that I made this code in XE5, you need to check XE6 compatibility):
TGlass = class(TControl)
private
FBlur: TBlurEffect;
FParentScreenshotBitmap: TBitmap;
function GetSoftness: Single;
procedure SetSoftness(Value: Single);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent);
destructor Destroy; override;
property Softness: Single read GetSoftness write SetSoftness;
end;
{ TGlass }
constructor TGlass.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
// Create parent background
FParentScreenshotBitmap := TBitmap.Create(0, 0);
// Create blur
FBlur := TBlurEffect.Create(nil);
FBlur.Softness := 0.6;
end;
destructor TGlass.Destroy;
begin
FBlur.Free;
FParentScreenshotBitmap.Free;
inherited Destroy;
end;
function TGlass.GetSoftness: Single;
begin
Result := FBlur.Softness;
end;
procedure TGlass.SetSoftness(Value: Single);
begin
FBlur.Softness := Value;
end;
procedure TGlass.Paint;
var
ParentWidth: Single;
ParentHeight: Single;
procedure DefineParentSize;
begin
ParentWidth := 0;
ParentHeight := 0;
if Parent is TCustomForm then
begin
ParentWidth := (Parent as TCustomForm).ClientWidth;
ParentHeight := (Parent as TCustomForm).ClientHeight;
end;
if Parent is TControl then
begin
ParentWidth := (Parent as TControl).Width;
ParentHeight := (Parent as TControl).Height;
end;
end;
function IsBitmapSizeChanged(ABitmap: TBitmap; const ANewWidth, ANewHeight: Single): Boolean;
begin
Result := not SameValue(ANewWidth * ABitmap.BitmapScale, ABitmap.Width) or
not SameValue(ANewHeight * ABitmap.BitmapScale, ABitmap.Height);
end;
procedure MakeParentScreenshot;
var
Form: TCommonCustomForm;
Child: TFmxObject;
ParentControl: TControl;
begin
if FParentScreenshotBitmap.Canvas.BeginScene then
try
FDisablePaint := True;
if Parent is TCommonCustomForm then
begin
Form := Parent as TCommonCustomForm;
for Child in Form.Children do
if (Child is TControl) and (Child as TControl).Visible then
begin
ParentControl := Child as TControl;
ParentControl.PaintTo(FParentScreenshotBitmap.Canvas, ParentControl.ParentedRect);
end;
end
else
(Parent as TControl).PaintTo(FParentScreenshotBitmap.Canvas, RectF(0, 0, ParentWidth, ParentHeight));
finally
FDisablePaint := False;
FParentScreenshotBitmap.Canvas.EndScene;
end;
end;
begin
// Make screenshot of Parent control
DefineParentSize;
if IsBitmapSizeChanged(FParentScreenshotBitmap, ParentWidth, ParentHeight) then
FParentScreenshotBitmap.SetSize(Round(ParentWidth), Round(ParentHeight));
MakeParentScreenshot;
// Apply glass effect
Canvas.BeginScene;
try
FBlur.ProcessEffect(Canvas, FParentScreenshotBitmap, FBlur.Softness);
Canvas.DrawBitmap(FParentScreenshotBitmap, ParentedRect, LocalRect, 1, TRUE);
finally
Canvas.EndScene;
end;
end;
To use, just instantiate TGlass on top of any control, it should make the desired "glassy" effect that you are looking for
Problem
I asked this question before and deleted just because 1) it seemed like more work than I wanted to do, and 2) I went about asking my question poorly and it got closed. But, after doing more research, I've decided I will revisit this feature/question/how-to I am attempting/wanting to create a blurred overlay as seen in the picture below. The obvious FMX.effect to use would be the 'Blur' effect. My question would be: how do I go about rendering the image the overlay would cover, or copying the image in an effective manner to blur for the overlay? I have thought about using just two of the same bitmap, one for the background and one to blur but then I wouldn't be capture 'blur-ness' of controls or anything else on top of the original background. I also would think that if I were to have the overlay scroll into and out of view, then it would not look/appear as I would want it. Considering the above, it all leads me to believe I need to dynamically capture the background to be blurred as the overlay scrolls/comes into view. How do I go about doing this and capturing current displayed screen content in Delphi XE6? Not sure where to even start. I do not own image *