unit EpIIForms;

interface

{$I EpIIVer.inc}

uses
  Classes, Windows, SysUtils, Forms, Controls, Graphics, KsBitmap, KsForms, 
  EpIIStyles, EpIIVersion;

type

{ TEpForm class}

  TEpForm = class(TKsCustomForm)
  private
    FBackground: TEpBackground;
    FBorder: TepBorder;
    FRegion: HRgn;
    FMask: TBitmap;
    FMaskBitmap: TKsBitmap;
    function GetVersion: TEpVersion;
    procedure SetVersion(const Value: TEpVersion);
    procedure SetBackground(const Value: TEpBackground);
    procedure SetBorder(const Value: TepBorder);
    procedure SetMask(const Value: TBitmap);
  protected
    { override }
    function GetClientRect: TRect; override;
    function GetHitTest(X, Y: integer): TKsHitTest; override;
    function GetRegion: HRgn; override;
    function GetMinTrackSize: TPoint; override;
    procedure PaintClientArea(Buffer: TKsBitmap); override;
    procedure PaintNCArea(Buffer: TKsBitmap); override;
    { }
    procedure PaintBackground(Buffer: TKsBitmap);
    procedure PaintBorder(Buffer: TKsBitmap);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
  published
    { It's possible to draw the background for the form. Based on TEpBackground class.
      See Also:
        TEpBackground
    }
    property Background: TEpBackground read FBackground write SetBackground;
    property Blend;
    property BlendValue;
    { It's possible to draw the border for the form. Based on TEpBorder class.
      See Also:
        TEpBorder
    }
    property Border: TepBorder read FBorder write SetBorder;
    property BorderStyle;
    property BorderIcons;
    property CanMove;
    property CanResize;
    property Magnetic;
    { Specifies the region mask for the form. RGB(255, 0, 255) is a transparent. }
    property Mask: TBitmap read FMask write SetMask;
    property Version: TEpVersion read GetVersion write SetVersion stored False;
  end;

implementation {===============================================================}

uses KsUtils;

{ TEpForm }

constructor TEpForm.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Active := true;
  FEraseBkgnd := true;

  FBackground := TEpBackground.Create;
  FBorder := TEpBorder.Create;
  FMask := TBitmap.Create;
  FMaskBitmap := TKsBitmap.Create;
end;

destructor TEpForm.Destroy;
begin
  FMaskBitmap.Free;
  FMask.Free;
  FBorder.Free;
  FBackground.Free;

  inherited Destroy;
end;

procedure TEpForm.Loaded;
begin
  inherited Loaded;

  if not FMask.Empty then
  begin
    FMaskBitmap.Assign(FMask);
    Update;
  end;

  if not CanResize then
  begin
    Form.Width := FMaskBitmap.Width;
    Form.Height := FMaskBitmap.Height;
  end;
end;

{ Internal }

procedure TEpForm.PaintBackground(Buffer: TKsBitmap);
begin
  Background.Draw(Buffer, GetClientRect);
end;

procedure TEpForm.PaintBorder(Buffer: TKsBitmap);
begin
  if BorderStyle <> kbsNone then Exit;
  { Draw Border }
  FBorder.Draw(Buffer, Rect(0, 0, FWidth, FHeight), FRegion);
end;

{ Protected Routines ==========================================================}

function TEpForm.GetMinTrackSize: TPoint;
begin
  if BorderStyle = kbsNone then
    Result := Point(10, 10)
  else
    Result := inherited GetMinTrackSize;
end;

function TEpForm.GetClientRect: TRect;
begin
  if BorderStyle = kbsNone then
  begin
    Result := Rect(0, 0, FWidth, FHeight);
    InflateRect(Result, -FBorder.GetWidth, -FBorder.GetHeight); 
  end
  else
    Result := inherited GetClientRect;
end;

function TEpForm.GetHitTest(X, Y: integer): TKsHitTest;
var
  BW: integer;
begin
  if BorderStyle = kbsNone then
  begin
    Result := khtCaption;

    if CanResize then
    begin
      BW := FBorder.GetWidth;
      if BW < 3 then BW := 3;

      if not FMaskBitmap.Empty then
      begin
        { Custom region }
        if (X > FWidth div 2) and (Y > FHeight div 2) then
          if not PtInRegion(FRegion, X+BW, Y+BW) then
            Result := khtBottomRight;
        if (X < FWidth div 2) and (Y < FHeight div 2) then
           if not PtInRegion(FRegion, X-BW, Y-BW) then
            Result := khtTopLeft;
        if (X > FWidth div 2) and (Y < FHeight div 2) then
          if not PtInRegion(FRegion, X+BW, Y-BW) then
            Result := khtTopRight;
        if (X < FWidth div 2) and (Y > FHeight div 2) then
          if not PtInRegion(FRegion, X-BW, Y+BW) then
            Result := khtBottomLeft;
      end
      else
      begin
        { Rect region }
        if (X < BW) then Result := khtLeft;
        if (X > FWidth-BW) then Result := khtRight;
        if (Y < BW) then Result := khtTop;
        if (Y > FHeight-BW) then Result := khtBottom;

        if (X < BW) and (Y < BW) then Result := khtTopLeft;
        if (X > FWidth-BW) and (Y < BW) then Result := khtTopRight;
        if (X < BW) and (Y > FHeight-BW) then Result := khtBottomLeft;
        if (X > FWidth-BW) and (Y > FHeight-BW) then Result := khtBottomRight;
      end;
    end;
  end
  else
    Result := inherited GetHitTest(X, Y);
end;

function TEpForm.GetRegion: HRgn;
var
  RgnData: PRgnData;
  Size: integer;
begin
  if not FMaskBitmap.Empty then
  begin
    { Create bitmap }
    if CanResize then
    begin
      FMaskBitmap.SetSize(FWidth, FHeight);
      StretchBlt(FMaskBitmap.DC, 0, 0, FWidth, FHeight, FMask.Canvas.Handle,
        0, 0, FMask.Width, FMask.Height, SRCCOPY);
    end;
    { Create Region }
    Result := CreateRegionFromBitmap(FMaskBitmap, 0, 0);
    { Create copy }
    if BorderStyle = kbsNone then
    begin
      { Free old region }
      if FRegion <> 0 then
        DeleteObject(FRegion);
      { Create region copy }
      Size := GetRegionData(Result, 0, nil);
      if Size > 0 then
      begin
        GetMem(RgnData, Size);
        try
          GetRegionData(Result, Size, RgnData);
          FRegion := ExtCreateRegion(nil, Size, RgnData^);
        finally
          FreeMem(RgnData, Size);
        end;
      end;
    end;
  end
  else
    Result := inherited GetRegion;
end;

procedure TEpForm.PaintClientArea(Buffer: TKsBitmap);
begin
  PaintBackground(Buffer);
  PaintBorder(Buffer);
end;

procedure TEpForm.PaintNCArea(Buffer: TKsBitmap);
begin
  if BorderStyle = kbsNone then
  begin
    PaintBorder(Buffer);
  end
  else
    inherited;
end;

{ Properties ==================================================================}

function TEpForm.GetVersion: TEpVersion;
begin
  Result := EpVersion;
end;

procedure TEpForm.SetBackground(const Value: TEpBackground);
begin
  FBackground.Assign(Value);
end;

procedure TEpForm.SetVersion(const Value: TEpVersion);
begin
end;

procedure TEpForm.SetBorder(const Value: TepBorder);
begin
  FBorder.Assign(Value);
end;

procedure TEpForm.SetMask(const Value: TBitmap);
begin
  FMask.Assign(Value);
end;

end.

