unit AlertOverlay;

{
  Reusable overlays for spectrum-like bitmap surfaces.
}

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

interface

uses
  Graphics, Types, Math;

procedure DrawAlertOverlay(Target: TBitmap; C: TCanvas; W, H: Integer;
  const Title, Detail: string);

implementation

procedure BlendRect(Target: TBitmap; const Rct: TRect; R, G, B, Alpha: Byte);
var
  Y, X, InvA: Integer;
  Row: PByte;
  RR: TRect;
begin
  if (Target = nil) or (Alpha = 0) then Exit;
  RR := Rct;
  if RR.Left < 0 then RR.Left := 0;
  if RR.Top < 0 then RR.Top := 0;
  if RR.Right > Target.Width then RR.Right := Target.Width;
  if RR.Bottom > Target.Height then RR.Bottom := Target.Height;
  if (RR.Right <= RR.Left) or (RR.Bottom <= RR.Top) then Exit;

  InvA := 255 - Alpha;
  Target.BeginUpdate(False);
  try
    for Y := RR.Top to RR.Bottom - 1 do
    begin
      Row := PByte(Target.ScanLine[Y]);
      if Row = nil then Continue;
      Inc(Row, RR.Left * 4);
      for X := RR.Left to RR.Right - 1 do
      begin
{$IFDEF DARWIN}
        Row[1] := Byte((Alpha * R + InvA * Row[1]) div 255);
        Row[2] := Byte((Alpha * G + InvA * Row[2]) div 255);
        Row[3] := Byte((Alpha * B + InvA * Row[3]) div 255);
{$ELSE}
        Row[0] := Byte((Alpha * B + InvA * Row[0]) div 255);
        Row[1] := Byte((Alpha * G + InvA * Row[1]) div 255);
        Row[2] := Byte((Alpha * R + InvA * Row[2]) div 255);
{$ENDIF}
        Inc(Row, 4);
      end;
    end;
  finally
    Target.EndUpdate(False);
  end;
end;

procedure DrawAlertOverlay(Target: TBitmap; C: TCanvas; W, H: Integer;
  const Title, Detail: string);
const
  PAD      = 12;
  INNER_X  = 12;
  ACCENT_W = 4;
var
  R, AccentR: TRect;
  TW, DW, BoxW, BoxH: Integer;
begin
  if (Target = nil) or (C = nil) then Exit;
  if (W < 220) or (H < 60) then Exit;

  C.Font.Name := 'Courier New';
  C.Font.Style := [fsBold];
  C.Font.Size := 9;
  TW := C.TextWidth(Title);
  C.Font.Style := [];
  C.Font.Size := 7;
  DW := C.TextWidth(Detail);

  BoxW := Max(TW, DW) + INNER_X * 2 + ACCENT_W + 8;
  BoxH := 42;
  R := Rect(W - PAD - BoxW, PAD, W - PAD, PAD + BoxH);

  BlendRect(Target, R, $A8, $10, $16, 118);
  BlendRect(Target, Rect(R.Left, R.Top, R.Right, R.Top + 1), $FF, $68, $68, 80);

  C.Brush.Style := bsClear;
  C.Pen.Style := psSolid;
  C.Pen.Width := 1;
  C.Pen.Color := TColor($003838C8);
  C.Rectangle(R);

  AccentR := Rect(R.Left + 7, R.Top + 7, R.Left + 7 + ACCENT_W, R.Bottom - 7);
  C.Brush.Style := bsSolid;
  C.Brush.Color := TColor($002828F0);
  C.Pen.Style := psClear;
  C.FillRect(AccentR);

  C.Brush.Style := bsClear;
  C.Font.Name := 'Courier New';
  C.Font.Style := [fsBold];
  C.Font.Size := 9;
  C.Font.Color := TColor($008888FF);
  C.TextOut(R.Left + INNER_X + ACCENT_W + 8, R.Top + 7, Title);

  C.Font.Style := [];
  C.Font.Size := 7;
  C.Font.Color := TColor($00C8C8E8);
  C.TextOut(R.Left + INNER_X + ACCENT_W + 8, R.Top + 25, Detail);
end;

end.
