{==============================================================================

  SkinEngine VCL by Evgeny Kryukov
  Copyright (C) 2000-2001 by Evgeny Kryukov
  All rights reserved

  All contents of this file and all other files included in this archive
  are Copyright (C) 2001 Evgeny Kryukov. Use and/or distribution of
  them requires acceptance of the License Agreement.

  See License.txt for licence information

===============================================================================}

unit KsSkinObjects2;

{$I KsSkinVer.Inc}

interface

uses Windows, Classes, Sysutils, Messages, Controls, Graphics, Forms, KsBitmap,
  KsSkinObjects;

type

{ TSeLinkSkinObject class }

  TSeLinkSkinObject = class(TSeSkinObject)
  private
    FLinkControl: string;
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
  published
    { Specifies the linked VCL control by name }
    property LinkControl: string read FLinkControl write FLinkControl;
  end;

{ TSeActiveSkinObject class }

  TSeActiveSkinObject = class(TSeSkinObject)
  private
    FActiveColor: TColor;
    FActiveFont: TFont;
    procedure SetActiveFont(const Value: TFont);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Colors }
    procedure ChangeHue(DeltaHue: integer); override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
  published
    { Specifies the color in ssActive state }
    property ActiveColor: TColor read FActiveColor write FActiveColor;
    { Specifies the font in ssActive state }
    property ActiveFont: TFont read FActiveFont write SetActiveFont;
  end;

{ TSeBitmapSkinObject class }

  { The following table lists the possible values:
    <TABLE>
    Value                       Meaning
    -----                       -------
    tsTile                      Bitmap tile on the object
    tsStretch                   Bitmap stretch by object size
    tsCenter                    Bitmap centered
    </TABLE>
  }
  TscTileStyle = (tsTile, tsStretch, tsCenter);

  TSeBitmapSkinObject = class(TSeSkinObject)
  private
    FBitmap: TKsBitmapLink;
    FTileStyle: TscTileStyle;
    procedure SetBitmap(const Value: TKsBitmapLink);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterLoad; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Region }
    function CreateRegion: HRgn; override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
  published
    { Specifies the object's bitmap }
    property Bitmap: TKsBitmapLink read FBitmap write SetBitmap;
    { Specifies the dysplay tile style }
    property TileStyle: TscTileStyle read FTileStyle write FTileStyle;
  end;

{ TSeFormBitmapSkinObject class }

  TSeFormBitmapSkinObject = class(TSeBitmapSkinObject)
  private
    FInactiveBitmap: TKsBitmapLink;
    procedure SetInactiveBitmap(const Value: TKsBitmapLink);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterLoad; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
  published
    { Specifies the bitmap in ssInactive state }
    property InactiveBitmap: TKsBitmapLink read FInactiveBitmap write SetInactiveBitmap;
  end;

{ TSeSysButtonSkinObject class }

  TSeSysButtonSkinObject = class(TSeBitmapSkinObject)
  private
    FAction: TSeAction;
    FBitmapDown: TKsBitmapLink;
    FBitmapHover: TKsBitmapLink;
    FButtonState: TSeButtonState;
    FShift: TShiftState;
    FRollPanel: string;
    procedure DoAction;
    
    procedure SetAction(const Value: TSeAction);
    procedure SetBitmapDown(const Value: TKsBitmapLink);
    procedure SetBitmapHover(const Value: TKsBitmapLink);
  protected
    procedure SetState(const Value: TSeState); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterLoad; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
    procedure MouseDown(Button: TMouseButton; X, Y: integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
    procedure MouseUp(Button: TMouseButton; X, Y: integer); override;
    procedure MouseDouble(Button: TMouseButton; X, Y: integer); override;
  published
    { Specifies the click action }
    property Action: TSeAction read FAction write SetAction;
    { Specifies bitmap in ssHot state }
    property BitmapHover: TKsBitmapLink read FBitmapHover write SetBitmapHover;
    { Specifies bitmap in ssPressed state }
    property BitmapDown: TKsBitmapLink read FBitmapDown write SetBitmapDown;
    { Specifies the name og RollPanel, use id Action = ssRollPanel }
    property RollPanel: string read FRollPanel write FRollPanel;
  end;

{ TSeColorButtonObject class }

  TSeColorButtonObject = class(TSeSkinObject)
  private
    FHotColor: TColor;
    FHotFont: TFont;
    FPressedColor: TColor;
    FFocusedColor: TColor;
    FDisabledColor: TColor;
    FPressedFont: TFont;
    FDisabledFont: TFont;
    FFocusedFont: TFont;
    procedure SetDisabledColor(const Value: TColor);
    procedure SetDisabledFont(const Value: TFont);
    procedure SetFocusedColor(const Value: TColor);
    procedure SetFocusedFont(const Value: TFont);
    procedure SetHotColor(const Value: TColor);
    procedure SetHotFont(const Value: TFont);
    procedure SetPressedColor(const Value: TColor);
    procedure SetPressedFont(const Value: TFont);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
  published
    { Specifies the color is ssHot state }
    property HotColor: TColor read FHotColor write SetHotColor;
    { Specifies the font is ssHot state }
    property HotFont: TFont read FHotFont write SetHotFont;
    { Specifies the color is ssPressed state }
    property PressedColor: TColor read FPressedColor write SetPressedColor;
    { Specifies the font is ssPressed state }
    property PressedFont: TFont read FPressedFont write SetPressedFont;
    { Specifies the color is ssFocused state }
    property FocusedColor: TColor read FFocusedColor write SetFocusedColor;
    { Specifies the font is ssFocused state }
    property FocusedFont: TFont read FFocusedFont write SetFocusedFont;
    { Specifies the color is ssDisabled state }
    property DisabledColor: TColor read FDisabledColor write SetDisabledColor;
    { Specifies the font is ssDisabled state }
    property DisabledFont: TFont read FDisabledFont write SetDisabledFont;
  end;

{ TSeBitmapBoxObject class }

  TSeBitmapBoxObject = class(TSeBitmapSkinObject)
  private
    FBorderTileStyle: TscTileStyle;
    procedure SetBorderTileStyle(const Value: TscTileStyle);
  protected
    procedure DrawRect(Buffer: TKsBitmap; MarginRect, MarginDstRect: TRect;
      ATileStyle: TscTileStyle);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
    { Events }
    procedure MouseHover; override;
    procedure MouseLeave; override;
  published
    { Specifies the border tile style }
    property BorderTileStyle: TscTileStyle read FBorderTileStyle write SetBorderTileStyle;
  end;

{ TSeActiveBitmapBoxObject class }

  TSeActiveBitmapBoxObject = class(TSeBitmapBoxObject)
  private
    FFocusedBitmap: TKsBitmapLink;
    procedure SetFocusedBitmap(const Value: TKsBitmapLink);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterLoad; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
  published
    { Specifies the bitmap in ssFocused state }
    property FocusedBitmap: TKsBitmapLink read FFocusedBitmap write SetFocusedBitmap;
  end;

{ TSeButtonBitmapBoxObject class }

  TSeButtonBitmapBoxObject = class(TSeBitmapBoxObject)
  private
    FFocusedBitmap: TKsBitmapLink;
    FHotBitmap: TKsBitmapLink;
    FPressedBitmap: TKsBitmapLink;
    FDisabledBitmap: TKsBitmapLink;
    procedure SetFocusedBitmap(const Value: TKsBitmapLink);
    procedure SetDisabledBitmap(const Value: TKsBitmapLink);
    procedure SetHotBitmap(const Value: TKsBitmapLink);
    procedure SetPressedBitmap(const Value: TKsBitmapLink);
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterLoad; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Drawing }
    procedure Draw(Buffer: TKsBitmap); override;
  published
    { Specifies the bitmap in ssHot state }
    property HotBitmap: TKsBitmapLink read FHotBitmap write SetHotBitmap;
    { Specifies the bitmap in ssFocused state }
    property FocusedBitmap: TKsBitmapLink read FFocusedBitmap write SetFocusedBitmap;
    { Specifies the bitmap in ssPressed state }
    property PressedBitmap: TKsBitmapLink read FPressedBitmap write SetPressedBitmap;
    { Specifies the bitmap in ssDisabled state }
    property DisabledBitmap: TKsBitmapLink read FDisabledBitmap write SetDisabledBitmap;
  end;

{ TSeRollPanelObject class }

  TSeRollPanelObject = class(TSeSkinObject)
  private
    FRollValue: integer;
    FRollKind: TSeRollKind;
    FOldValue: integer;
    procedure OwnerUpdate;
  protected
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Assign, Copy }
    procedure Assign(Source: TPersistent); override;
    { Roll }
    procedure Roll;
  published
    { Specifies the roll direction }
    property RollKind: TSeRollKind read FRollKind write FRollKind;
    { Specifies the value of width (or height) in rolled state }
    property RollValue: integer read FRollValue write FRollValue;
  end;

{ Registration }

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

uses KsUtils, KsForms, KsSkinForms;

{ TSeLinkSkinObject ===========================================================}

constructor TSeLinkSkinObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TSeLinkSkinObject.Destroy;
begin
  inherited Destroy;
end;

procedure TSeLinkSkinObject.Assign(Source: TPersistent);
begin
  if Source is TSeLinkSkinObject then
  begin
    inherited Assign(Source);
    FLinkControl := (Source as TSeLinkSkinObject).FLinkControl;
  end
  else
    inherited;
end;

procedure TSeLinkSkinObject.Draw(Buffer: TKsBitmap);
var
  R: TRect;
begin
  if State <> ssDesign then Exit;
  
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;
  
  Buffer.FillRect(BoundsRect, ckWhite);
  Buffer.DrawEdge(BoundsRect, ckBlack, ckBlack);

  Buffer.Font.Name := 'Arial';
  Buffer.Font.Style := [fsItalic];
  Buffer.Font.Color := clBlack;
  R := BoundsRect;
  Buffer.DrawText(FLinkControl, R, DT_CENTER or DT_SINGLELINE or DT_VCENTER);
end;

procedure TSeLinkSkinObject.MouseHover;
begin
  inherited;

end;

procedure TSeLinkSkinObject.MouseLeave;
begin
  inherited;

end;

{ TSeBitmapSkinObject =========================================================}

constructor TSeBitmapSkinObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FBitmap := TKsBitmapLink.Create;
end;

destructor TSeBitmapSkinObject.Destroy;
begin
  FBitmap.Free;
  inherited Destroy;
end;

procedure TSeBitmapSkinObject.AfterLoad;
var
  NewLink: TKsBitmapLink;
begin
  inherited AfterLoad;
  if Bitmaps <> nil then
  begin
    NewLink := Bitmaps.GetBitmapLink(FBitmap.Name, FBitmap.Rect);
    if NewLink <> nil then
    begin
      FBitmap.Free;
      FBitmap := NewLink;
    end;
  end;
end;

procedure TSeBitmapSkinObject.Assign(Source: TPersistent);
begin
  if Source is TSeBitmapSkinObject then
  begin
    inherited Assign(Source);
    Bitmap := (Source as TSeBitmapSkinObject).Bitmap;
    FTileStyle := (Source as TSeBitmapSkinObject).FTileStyle;
  end
  else
    inherited;
end;

procedure TSeBitmapSkinObject.Draw(Buffer: TKsBitmap);
var
  DstRect, R: TRect;
  i, j: integer;
  W, H: integer;
  DW, DH: integer;
begin
  if not FBitmap.Assigned then Exit;
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;

  case FTileStyle of
    tsTile: begin
      FBitmap.Bitmap.Blend := true;
      FBitmap.Bitmap.DrawTile(Buffer, BoundsRect, FBitmap.Rect);
      FBitmap.Bitmap.Blend := false;
    end;
    tsStretch: begin
      FBitmap.Bitmap.Blend := true;
      FBitmap.Bitmap.DrawStretch(Buffer, BoundsRect, FBitmap.Rect);
      FBitmap.Bitmap.Blend := false;
    end;
    tsCenter: begin
      R := BoundsRect;
      FBitmap.Bitmap.Blend := true;
      FBitmap.Draw(Buffer, Left + (Width - RectWidth(R)) div 2,
        Top + (Height - RectHeight(R)) div 2);
      FBitmap.Bitmap.Blend := false;
    end;
  end;

  DrawText(Buffer);
end;

function TSeBitmapSkinObject.CreateRegion: HRgn;
var
  TempImage: TKsBitmap;
  SaveRect: TRect;
begin
  if not FBitmap.Assigned then Exit;
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;
  if Kind = skClient then
  begin
    Result := CreateRectRgn(Left, Top, Left + Width, Top + Height);
    Exit;
  end;

  { Make mask from bitmap }
  SaveRect := BoundsRect;
  try
    { Set new rect }
    BoundsRect := Rect(0, 0, Width, Height);
    { Draw to TempImage }
    TempImage := TKsBitmap.Create;
    try
      TempImage.SetSize(Width, Height);
      TempImage.Clear(ckTransparent);
      { Draw to Temp }
      Draw(TempImage);
      { Create region }
      Result := CreateRegionFromBitmap(TempImage, SaveRect.Left, SaveRect.Top);
    finally
      TempImage.Free;
    end;
  finally
    BoundsRect := SaveRect;
  end;
end;

procedure TSeBitmapSkinObject.MouseHover;
begin
end;

procedure TSeBitmapSkinObject.MouseLeave;
begin
end;

procedure TSeBitmapSkinObject.SetBitmap(const Value: TKsBitmapLink);
begin
  FBitmap.Assign(Value);
end;

{ TSeFormBitmapSkinObject }

constructor TSeFormBitmapSkinObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FInactiveBitmap := TKsBitmapLink.Create;
end;

destructor TSeFormBitmapSkinObject.Destroy;
begin
  FInactiveBitmap.Free;
  inherited Destroy;
end;

procedure TSeFormBitmapSkinObject.AfterLoad;
var
  NewLink: TKsBitmapLink;
begin
  inherited AfterLoad;
  if Bitmaps <> nil then
  begin
    NewLink := Bitmaps.GetBitmapLink(FInactiveBitmap.Name, FInactiveBitmap.Rect);
    if NewLink <> nil then
    begin
      FInactiveBitmap.Free;
      FInactiveBitmap := NewLink;
    end;
  end;
end;

procedure TSeFormBitmapSkinObject.Assign(Source: TPersistent);
begin
  if Source is TSeFormBitmapSkinObject then
  begin
    inherited Assign(Source);
    FInactiveBitmap.Assign((Source as TSeFormBitmapSkinObject).InactiveBitmap);
  end
  else
    inherited;
end;

procedure TSeFormBitmapSkinObject.Draw(Buffer: TKsBitmap);
var
  SaveBitmap: TKsBitmapLink;
begin
  if (not Active) and (InactiveBitmap.Assigned) then
  begin
    SaveBitmap := FBitmap;
    try
      FBitmap := FInactiveBitmap;
      inherited Draw(Buffer);
    finally
      FBitmap := SaveBitmap;
    end;
  end
  else
    inherited Draw(Buffer);
end;

procedure TSeFormBitmapSkinObject.MouseHover;
begin
  inherited;

end;

procedure TSeFormBitmapSkinObject.MouseLeave;
begin
  inherited;

end;

procedure TSeFormBitmapSkinObject.SetInactiveBitmap(
  const Value: TKsBitmapLink);
begin
  FInactiveBitmap.Assign(Value);
end;

{ TSeSysButtonSkinObject }

constructor TSeSysButtonSkinObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Kind := skSysButton;

  FBitmapHover := TKsBitmapLink.Create;
  FBitmapDown := TKsBitmapLink.Create;
end;

destructor TSeSysButtonSkinObject.Destroy;
begin
  FBitmapHover.Free;
  FBitmapDown.Free;
  inherited Destroy;
end;

procedure TSeSysButtonSkinObject.AfterLoad;
var
  NewLink: TKsBitmapLink;
begin
  inherited AfterLoad;
  if Bitmaps <> nil then
  begin
    { Hover }
    NewLink := Bitmaps.GetBitmapLink(FBitmapHover.Name, FBitmapHover.Rect);
    if NewLink <> nil then
    begin
      FBitmapHover.Free;
      FBitmapHover := NewLink;
    end;
    { Down }
    NewLink := Bitmaps.GetBitmapLink(FBitmapDown.Name, FBitmapDown.Rect);
    if NewLink <> nil then
    begin
      FBitmapDown.Free;
      FBitmapDown := NewLink;
    end;
  end;
end;

procedure TSeSysButtonSkinObject.Assign(Source: TPersistent);
begin
  if Source is TSeSysButtonSkinObject then
  begin
    inherited Assign(Source);
    FBitmapHover.Assign((Source as TSeSysButtonSkinObject).BitmapHover);
    FBitmapDown.Assign((Source as TSeSysButtonSkinObject).BitmapDown);
    FAction := (Source as TSeSysButtonSkinObject).FAction;
    FRollPanel := (Source as TSeSysButtonSkinObject).FRollPanel;
  end
  else
    inherited;
end;

procedure TSeSysButtonSkinObject.SetState(const Value: TSeState);
var
  SkinForm: TSeSkinForm;
begin
  inherited SetState(Value);

  SkinForm := TSeSkinForm(GetSkinForm);

  if SkinForm = nil then Exit;

  case State of
    ssNormal: begin
      Visible := true;
      if FAction = sbaRestore then Visible := false;
      if FAction = sbaRollDown then Visible := false;
    end;
    ssMaximized: begin
      Visible := true;
      if FAction = sbaMaximize then Visible := false;
      if FAction = sbaRollDown then Visible := false;
    end;
    ssMinimized: begin
      Visible := true;
      if FAction = sbaMinimize then Visible := false;
      if FAction = sbaMaximize then Visible := false;
      if FAction = sbaRollUp then Visible := false;
      if FAction = sbaRollDown then Visible := false;
    end;
    ssRollup: begin
      Visible := true;
      if FAction = sbaRestore then Visible := false;
      if FAction = sbaRollUp then Visible := false;
    end;
  end;
  
  case FAction of
    sbaNone: ;
    sbaClose: if not (kbiClose in SkinForm.BorderIcons) then Visible := false;
    sbaHelp: if not (kbiHelp in SkinForm.BorderIcons) then Visible := False;
    sbaMinimize: if not (kbiMinimize in SkinForm.BorderIcons) then Visible := False;
    sbaMaximize: if not (kbiMaximize in SkinForm.BorderIcons) then Visible := False;
    sbaRestore: if not (kbiMaximize in SkinForm.BorderIcons) then Visible := False;
    sbaRollUp: if not (kbiRollUp in SkinForm.BorderIcons) then Visible := False;
    sbaRollDown: if not (kbiRollUp in SkinForm.BorderIcons) then Visible := False;
    sbaTray: if not (kbiTray in SkinForm.BorderIcons) then Visible := False;
    sbaSysMenu: if not (kbiSystemMenu in SkinForm.BorderIcons) then Visible := False;
    sbaRollPanel: ;
  end;
end;

procedure TSeSysButtonSkinObject.DoAction;
var
  SkinForm: TSeSkinForm;
  SkinObject: TSeSkinObject;
  OwnerObject: TSeSkinObject;
begin
  SkinForm := TSeSkinForm(GetSkinForm);
  case FAction of
    sbaClose: if SkinForm <> nil then begin
      SkinForm.Close;
    end;
    sbaHelp: if SkinForm <> nil then begin
      SkinForm.Help;
    end;
    sbaMinimize: if SkinForm <> nil then begin
      SkinForm.Minimize;
    end;
    sbaMaximize: if SkinForm <> nil then begin
      SkinForm.Maximize;
    end;
    sbaRestore: if SkinForm <> nil then begin
      SkinForm.Restore;
    end;
    sbaRollup: if SkinForm <> nil then begin
      SkinForm.Rollup;
    end;
    sbaRollDown: if SkinForm <> nil then begin
      SkinForm.Restore;
    end;
    sbaTray: if SkinForm <> nil then begin
      SkinForm.MinToTray;
    end;
    sbaSysMenu: if SkinForm <> nil then begin
      SkinForm.SysMenu;
    end;
    sbaRollPanel: if SkinForm <> nil then begin
      { Roll}
      OwnerObject := Self;
      while OwnerObject.Owner <> nil do
        OwnerObject := (OwnerObject.Owner as TSeSkinObject);
        
      SkinObject := OwnerObject.FindObjectByName(FRollPanel);
      if SkinObject is TSeRollPanelObject then
        with SkinObject as TSeRollPanelObject do
          Roll;
    end;
    sbaCustom: if SkinForm <> nil then
      if Assigned(SkinForm.OnCustomAction) then SkinForm.OnCustomAction(Self);
  end;
end;

procedure TSeSysButtonSkinObject.Draw(Buffer: TKsBitmap);
var
  SaveBitmap: TKsBitmapLink;
  IHandle, IHandle2 : HICON;
  IconX, IconY : integer;
  ID: boolean;
  R: TRect;
begin
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;

  if Action = sbaSysMenu then
  begin
    if ParentControl = nil then Exit;
    if not (ParentControl is TForm) then Exit;

    R := BoundsRect;

    ID := false;
    if TForm(ParentControl).Icon.Handle <> 0 then
      IHandle := TForm(ParentControl).Icon.Handle
    else
      if Application.Icon.Handle <> 0 then
        IHandle := Application.Icon.Handle
      else
      begin
        IHandle := LoadIcon(0, IDI_APPLICATION);
        ID := true;
      end;
    IconX := GetSystemMetrics(SM_CXSMICON);
    if IconX = 0 then IconX := GetSystemMetrics(SM_CXSIZE);
    IconY := GetSystemMetrics(SM_CYSMICON);
    if IconY = 0 then IconY := GetSystemMetrics(SM_CYSIZE);
    IHandle2 := CopyImage(IHandle, IMAGE_ICON, IconX, IconY, LR_COPYFROMRESOURCE);
    DrawIconEx(Buffer.DC, R.Left, R.Top, IHandle2, 0, 0, 0, 0, DI_NORMAL);
    DestroyIcon(IHandle2);
    if ID then DestroyIcon(IHandle);
    Exit;
  end;

  case FButtonState of
    bsNormal: inherited Draw(Buffer);
    bsHover: begin
      SaveBitmap := FBitmap;
      try
        if FBitmapHover.Assigned then
          FBitmap := FBitmapHover;
        inherited Draw(Buffer);
      finally
        FBitmap := SaveBitmap;
      end;
    end;
    bsDown: begin
      SaveBitmap := FBitmap;
      try
        if FBitmapDown.Assigned then
          FBitmap := FBitmapDown;
        inherited Draw(Buffer);
      finally
        FBitmap := SaveBitmap;
      end;
    end;
  end;
end;

procedure TSeSysButtonSkinObject.MouseHover;
begin
  if ssLeft in FShift then
    FButtonState := bsDown
  else
    FButtonState := bsHover;
  Invalidate;
end;

procedure TSeSysButtonSkinObject.MouseLeave;
begin
  FButtonState := bsNormal;
  Invalidate;
end;

procedure TSeSysButtonSkinObject.MouseDouble(Button: TMouseButton; X, Y: integer);
var
  SkinForm: TSeSkinForm;
  SkinObject: TSeSkinObject;
  OwnerObject: TSeSkinObject;
begin
  if (Button = mbLeft) and (FAction = sbaSysMenu) then
  begin
    SkinForm := TSeSkinForm(GetSkinForm);
    if SkinForm <> nil then
      SkinForm.Close;
  end;
end;

procedure TSeSysButtonSkinObject.MouseDown(Button: TMouseButton; X,
  Y: integer);
begin
  if Button = mbLeft then
  begin
    FButtonState := bsDown;
    Invalidate;
  end;
end;

procedure TSeSysButtonSkinObject.MouseMove(Shift: TShiftState; X,
  Y: integer);
var
  Pos: TPoint;
begin
  if (FButtonState = bsDown) and (ssLeft in Shift) then
  begin
    FButtonState := bsDown;
    Invalidate;
  end
  else
  begin
    { Show Hint }
    Pos := Point(Left, Top);
    if ParentControl <> nil then
      Pos := ParentControl.ClientToScreen(Pos);
    {$IFDEF SE_COMPILER5}
    Application.ActivateHint(Pos);
    {$ENDIF}
  end;

  FShift := Shift;
end;

procedure TSeSysButtonSkinObject.MouseUp(Button: TMouseButton; X,
  Y: integer);
begin
  if (FButtonState = bsDown) and (Button = mbLeft) then
  begin
    FButtonState := bsHover;
    Invalidate;

    DoAction;
  end;
  FShift := [];
end;

procedure TSeSysButtonSkinObject.SetAction(const Value: TSeAction);
begin
  FAction := Value;
end;

procedure TSeSysButtonSkinObject.SetBitmapDown(const Value: TKsBitmapLink);
begin
  FBitmapDown.Assign(Value);
end;

procedure TSeSysButtonSkinObject.SetBitmapHover(
  const Value: TKsBitmapLink);
begin
  FBitmapHover.Assign(Value);
end;

{ TSeActiveSkinObject =========================================================}

constructor TSeActiveSkinObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FActiveFont := TFont.Create;
end;

destructor TSeActiveSkinObject.Destroy;
begin
  FActiveFont.Free;
  inherited Destroy;
end;

procedure TSeActiveSkinObject.Assign(Source: TPersistent);
begin
  if Source is TSeActiveSkinObject then
  begin
    inherited Assign(Source);
    ActiveColor := (Source as TSeActiveSkinObject).ActiveColor;
    ActiveFont := (Source as TSeActiveSkinObject).ActiveFont;
  end
  else
    inherited;
end;

procedure TSeActiveSkinObject.ChangeHue(DeltaHue: integer);
begin
  inherited;
  FActiveColor := KColorToColor(KsBitmap.ChangeHue(KColor(FActiveColor), DeltaHue));
  FActiveFont.Color := KColorToColor(KsBitmap.ChangeHue(KColor(FActiveFont.Color), DeltaHue));
end;

procedure TSeActiveSkinObject.Draw(Buffer: TKsBitmap);
var
  SaveColor: TColor;
  SaveFont: TFont;
begin
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;
  
  if (State = ssFocused) or (State = ssHot) then
  begin
    SaveFont := Font;
    SaveColor := Color;
    try
      FColor := FActiveColor;
      FFont := FActiveFont;
      inherited Draw(Buffer);
    finally
      FFont := SaveFont;
      FColor := SaveColor;
    end;
  end
  else
    inherited Draw(Buffer);
end;

procedure TSeActiveSkinObject.MouseHover;
begin
  State := ssHot;
  Invalidate;
end;

procedure TSeActiveSkinObject.MouseLeave;
begin
  State := ssNormal;
  Invalidate;
end;

procedure TSeActiveSkinObject.SetActiveFont(const Value: TFont);
begin
  FActiveFont.Assign(Value);
end;

{ TSeColorButtonObject ========================================================}

constructor TSeColorButtonObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FHotFont := TFont.Create;
  FPressedFont := TFont.Create;
  FDisabledFont := TFont.Create;
  FFocusedFont := TFont.Create;
end;

destructor TSeColorButtonObject.Destroy;
begin
  FFocusedFont.Free;
  FDisabledFont.Free;
  FPressedFont.Free;
  FHotFont.Free;
  inherited Destroy;
end;

procedure TSeColorButtonObject.Assign(Source: TPersistent);
begin
  if Source is TSeColorButtonObject then
  begin
    inherited Assign(Source);
    HotFont := (Source as TSeColorButtonObject).FHotFont;
    HotColor := (Source as TSeColorButtonObject).FHotColor;
    PressedFont := (Source as TSeColorButtonObject).FPressedFont;
    PressedColor := (Source as TSeColorButtonObject).FPressedColor;
    FocusedFont := (Source as TSeColorButtonObject).FFocusedFont;
    FocusedColor := (Source as TSeColorButtonObject).FFocusedColor;
    DisabledFont := (Source as TSeColorButtonObject).FDisabledFont;
    DisabledColor := (Source as TSeColorButtonObject).FDisabledColor;
  end
  else
    inherited;
end;

procedure TSeColorButtonObject.Draw(Buffer: TKsBitmap);
var
  SaveFont: TFont;
  SaveColor: TColor;
begin
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;
  
  SaveFont := TFont.Create;
  try
    SaveFont.Assign(Font);
    SaveColor := Color;

    case State of
      ssHot: begin
        Font.Assign(FHotFont);
        Color := FHotColor;
      end;
      ssFocused: begin
        Font.Assign(FFocusedFont);
        Color := FFocusedColor;
      end;
      ssPressed: begin
        Font.Assign(FPressedFont);
        Color := FPressedColor;
      end;
      ssDisabled: begin
        Font.Assign(FDisabledFont);
        Color := FDisabledColor;
      end;
    end;
    inherited Draw(Buffer);
  finally
    Font.Assign(SaveFont);
    Color := SaveColor;

    SaveFont.Free;
  end;
end;

procedure TSeColorButtonObject.MouseHover;
begin
  inherited;
end;

procedure TSeColorButtonObject.MouseLeave;
begin
  inherited;
end;

procedure TSeColorButtonObject.SetDisabledColor(const Value: TColor);
begin
  FDisabledColor := Value;
end;

procedure TSeColorButtonObject.SetDisabledFont(const Value: TFont);
begin
  FDisabledFont.Assign(Value);
end;

procedure TSeColorButtonObject.SetFocusedColor(const Value: TColor);
begin
  FFocusedColor := Value;
end;

procedure TSeColorButtonObject.SetFocusedFont(const Value: TFont);
begin
  FFocusedFont.Assign(Value);
end;

procedure TSeColorButtonObject.SetHotColor(const Value: TColor);
begin
  FHotColor := Value;
end;

procedure TSeColorButtonObject.SetHotFont(const Value: TFont);
begin
  FHotFont.Assign(Value);
end;

procedure TSeColorButtonObject.SetPressedColor(const Value: TColor);
begin
  FPressedColor := Value;
end;

procedure TSeColorButtonObject.SetPressedFont(const Value: TFont);
begin
  FPressedFont.Assign(Value);
end;

{ TSeBitmapBoxObject ==========================================================}

constructor TSeBitmapBoxObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

procedure TSeBitmapBoxObject.Assign(Source: TPersistent);
begin
  if Source is TSeBitmapBoxObject then
  begin
    inherited Assign(Source);
    BorderTileStyle := (Source as TSeBitmapBoxObject).FBorderTileStyle;
  end
  else
    inherited;
end;

destructor TSeBitmapBoxObject.Destroy;
begin
  inherited Destroy;
end;

procedure TSeBitmapBoxObject.DrawRect(Buffer: TKsBitmap; MarginRect, MarginDstRect: TRect;
  ATileStyle: TscTileStyle);
var
  DstRect, R: TRect;
  i, j: integer;
  W, H: integer;
  DW, DH: integer;
begin
  W := RectWidth(MarginRect);
  H := RectHeight(MarginRect);
  if W * H = 0 then Exit;
   
  case ATileStyle of
    tsTile: begin
      OffsetRect(MarginDstRect, Left, Top);
      FBitmap.Bitmap.DrawTile(Buffer, MarginDstRect, MarginRect);
    end;
    tsStretch: begin
      OffsetRect(MarginDstRect, Left, Top);
      FBitmap.Bitmap.DrawStretch(Buffer, MarginDstRect, MarginRect);
    end;
    tsCenter: begin
      R := BoundsRect;
      FBitmap.Draw(Buffer, Left + (Width - RectWidth(R)) div 2,
        Top + (Height - RectHeight(R)) div 2);
    end;
  end;
end;

procedure TSeBitmapBoxObject.Draw(Buffer: TKsBitmap);
var
  SrcRect, DstRect: TRect;
begin
  if not FBitmap.Assigned then Exit;
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;

  if (MarginLeft = 0) and (MarginTop = 0) and
     (MarginRight = 0) and (MarginBottom = 0) then
  begin
    inherited Draw(Buffer);
    Exit;
  end;

  { Draw Face }

  FBitmap.Bitmap.Blend := true;
  
  { Draw Center Rect }
  with FBitmap.Rect do
    SrcRect := Rect(Left + MarginLeft, Top + MarginTop, Right - MarginRight,
      Bottom - MarginBottom);
  DstRect := Rect(MarginLeft, MarginTop, Width - MarginRight, Height - MarginBottom);
  DrawRect(Buffer, SrcRect, DstRect, FTileStyle);

  { Draw Top Border }
  with FBitmap.Rect do
    SrcRect := Rect(Left + MarginLeft, Top, Right - MarginRight,
      Top + MarginTop);
  DstRect := Rect(MarginLeft, 0, Width - MarginRight, MarginTop);
  DrawRect(Buffer, SrcRect, DstRect, FBorderTileStyle);

  { Draw Bottom Border }
  with FBitmap.Rect do
    SrcRect := Rect(Left + MarginLeft, Bottom - MarginBottom, Right - MarginRight,
      Bottom);
  DstRect := Rect(MarginLeft, Height - MarginBottom, Width - MarginRight, Height);
  DrawRect(Buffer, SrcRect, DstRect, FBorderTileStyle);

  { Draw Left Border }
  with FBitmap.Rect do
    SrcRect := Rect(Left, Top + MarginTop, Left + MarginLeft,
      Bottom - MarginBottom);
  DstRect := Rect(0, MarginTop, MarginLeft, Height - MarginBottom);
  DrawRect(Buffer, SrcRect, DstRect, FBorderTileStyle);

  { Draw Right Border }
  with FBitmap.Rect do
    SrcRect := Rect(Right - MarginRight, Top + MarginTop, Right,
      Bottom - MarginBottom);
  DstRect := Rect(Width - MarginRight, MarginTop, Width,
    Height - MarginBottom);
  DrawRect(Buffer, SrcRect, DstRect, FBorderTileStyle);

  { Draw Angles }
  with FBitmap.Rect do
    SrcRect := Rect(Left, Top, Left + MarginLeft, Top + MarginTop);
  FBitmap.Bitmap.Draw(Buffer, Left, Top, SrcRect);
  with FBitmap.Rect do
    SrcRect := Rect(Right - MarginRight, Top, Right, Top + MarginTop);
  FBitmap.Bitmap.Draw(Buffer, Left + Width - MarginRight, Top, SrcRect);

  with FBitmap.Rect do
    SrcRect := Rect(Left, Bottom - MarginBottom, Left + MarginLeft, Bottom);
  FBitmap.Bitmap.Draw(Buffer, Left, Top + Height - MarginBottom, SrcRect);

  with FBitmap.Rect do
    SrcRect := Rect(Right - MarginRight, Bottom - MarginBottom, Right, Bottom);
  FBitmap.Bitmap.Draw(Buffer, Left + Width - MarginRight,
    Top + Height - MarginBottom, SrcRect);

  FBitmap.Bitmap.Blend := false;

  { Draw Text }
  DrawText(Buffer);
end;

procedure TSeBitmapBoxObject.MouseHover;
begin
  inherited;
end;

procedure TSeBitmapBoxObject.MouseLeave;
begin
  inherited;
end;

procedure TSeBitmapBoxObject.SetBorderTileStyle(const Value: TscTileStyle);
begin
  FBorderTileStyle := Value;
end;

{ TSeActiveBitmapBoxObject ====================================================}

constructor TSeActiveBitmapBoxObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FFocusedBitmap := TKsBitmapLink.Create;
end;

destructor TSeActiveBitmapBoxObject.Destroy;
begin
  FFocusedBitmap.Free;
  inherited Destroy;
end;

procedure TSeActiveBitmapBoxObject.AfterLoad;
var
  NewLink: TKsBitmapLink;
begin
  inherited AfterLoad;
  if Bitmaps <> nil then
  begin
    { Focused }
    NewLink := Bitmaps.GetBitmapLink(FFocusedBitmap.Name, FFocusedBitmap.Rect);
    if NewLink <> nil then
    begin
      FFocusedBitmap.Free;
      FFocusedBitmap := NewLink;
    end;
  end;
end;

procedure TSeActiveBitmapBoxObject.Assign(Source: TPersistent);
begin
  if Source is TSeActiveBitmapBoxObject then
  begin
    inherited Assign(Source);
    FocusedBitmap := (Source as TSeActiveBitmapBoxObject).FocusedBitmap;
  end
  else
    inherited;
end;

procedure TSeActiveBitmapBoxObject.Draw(Buffer: TKsBitmap);
var
  SaveBitmap: TKsBitmapLink;
begin
  if not FBitmap.Assigned then Exit;
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;

  if ((State = ssFocused) or (State = ssHot)) and (FFocusedBitmap.Assigned) then
  begin
    SaveBitmap := FBitmap;
    try
      FBitmap := FFocusedBitmap;

      inherited Draw(Buffer);
    finally
      FBitmap := SaveBitmap;
    end;
  end
  else
    inherited Draw(Buffer);
end;

procedure TSeActiveBitmapBoxObject.SetFocusedBitmap(
  const Value: TKsBitmapLink);
begin
  FFocusedBitmap.Assign(Value);
end;

{ TSeButtonBitmapBoxObject ====================================================}

constructor TSeButtonBitmapBoxObject.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FFocusedBitmap := TKsBitmapLink.Create;
  FHotBitmap := TKsBitmapLink.Create;
  FPressedBitmap := TKsBitmapLink.Create;
  FDisabledBitmap := TKsBitmapLink.Create;
end;

destructor TSeButtonBitmapBoxObject.Destroy;
begin
  FFocusedBitmap.Free;
  FHotBitmap.Free;
  FPressedBitmap.Free;
  FDisabledBitmap.Free;
  inherited Destroy;
end;

procedure TSeButtonBitmapBoxObject.AfterLoad;
var
  NewLink: TKsBitmapLink;
begin
  inherited AfterLoad;
  if Bitmaps <> nil then
  begin
    { Focused }
    NewLink := Bitmaps.GetBitmapLink(FFocusedBitmap.Name, FFocusedBitmap.Rect);
    if NewLink <> nil then
    begin
      FFocusedBitmap.Free;
      FFocusedBitmap := NewLink;
    end;
    { Hot }
    NewLink := Bitmaps.GetBitmapLink(FHotBitmap.Name, FHotBitmap.Rect);
    if NewLink <> nil then
    begin
      FHotBitmap.Free;
      FHotBitmap := NewLink;
    end;
    { Pressed }
    NewLink := Bitmaps.GetBitmapLink(FPressedBitmap.Name, FPressedBitmap.Rect);
    if NewLink <> nil then
    begin
      FPressedBitmap.Free;
      FPressedBitmap := NewLink;
    end;
    { Disabled }
    NewLink := Bitmaps.GetBitmapLink(FDisabledBitmap.Name, FDisabledBitmap.Rect);
    if NewLink <> nil then
    begin
      FDisabledBitmap.Free;
      FDisabledBitmap := NewLink;
    end;
  end;
end;

procedure TSeButtonBitmapBoxObject.Assign(Source: TPersistent);
begin
  if Source is TSeButtonBitmapBoxObject then
  begin
    inherited Assign(Source);
    FocusedBitmap := (Source as TSeButtonBitmapBoxObject).FocusedBitmap;
    HotBitmap := (Source as TSeButtonBitmapBoxObject).HotBitmap;
    DisabledBitmap := (Source as TSeButtonBitmapBoxObject).DisabledBitmap;
    PressedBitmap := (Source as TSeButtonBitmapBoxObject).PressedBitmap;
  end
  else
    inherited;
end;

procedure TSeButtonBitmapBoxObject.Draw(Buffer: TKsBitmap);
var
  SaveBitmap: TKsBitmapLink;
begin
  if not FBitmap.Assigned then Exit;
  if Width <= 0 then Exit;
  if Height <= 0 then Exit;

  if (State = ssFocused) and (FFocusedBitmap.Assigned) then
  begin
    SaveBitmap := FBitmap;
    try
      FBitmap := FFocusedBitmap;

      inherited Draw(Buffer);
    finally
      FBitmap := SaveBitmap;
    end;
    Exit;
  end;

  if (State = ssHot) and (FHotBitmap.Assigned) then
  begin
    SaveBitmap := FBitmap;
    try
      FBitmap := FHotBitmap;

      inherited Draw(Buffer);
    finally
      FBitmap := SaveBitmap;
    end;
    Exit;
  end;

  if (State = ssDisabled) and (FDisabledBitmap.Assigned) then
  begin
    SaveBitmap := FBitmap;
    try
      FBitmap := FDisabledBitmap;

      inherited Draw(Buffer);
    finally
      FBitmap := SaveBitmap;
    end;
    Exit;
  end;

  if (State = ssPressed) and (FPressedBitmap.Assigned) then
  begin
    SaveBitmap := FBitmap;
    try
      FBitmap := FPressedBitmap;

      inherited Draw(Buffer);
    finally
      FBitmap := SaveBitmap;
    end;
    Exit;
  end;

  inherited Draw(Buffer);
end;

procedure TSeButtonBitmapBoxObject.SetDisabledBitmap(const Value: TKsBitmapLink);
begin
  FDisabledBitmap.Assign(Value);
end;

procedure TSeButtonBitmapBoxObject.SetFocusedBitmap(const Value: TKsBitmapLink);
begin
  FFocusedBitmap.Assign(Value);
end;

procedure TSeButtonBitmapBoxObject.SetHotBitmap(const Value: TKsBitmapLink);
begin
  FHotBitmap.Assign(Value);
end;

procedure TSeButtonBitmapBoxObject.SetPressedBitmap(const Value: TKsBitmapLink);
begin
  FPressedBitmap.Assign(Value);
end;

{ TSeRollPanelObject }

constructor TSeRollPanelObject.Create(AOwner: TComponent);
begin
  inherited;

end;

destructor TSeRollPanelObject.Destroy;
begin
  inherited Destroy;
end;

procedure TSeRollPanelObject.Assign(Source: TPersistent);
begin
  if Source is TSeRollPanelObject then
  begin
    inherited Assign(Source);
    RollKind := (Source as TSeRollPanelObject).RollKind;
    RollValue := (Source as TSeRollPanelObject).RollValue;
  end
  else
    inherited;
end;

procedure TSeRollPanelObject.OwnerUpdate;
var
  SkinForm: TSeSkinForm;
begin
  if Owner = nil then Exit;

  SkinForm := TSeSkinForm(GetSkinForm);

  Application.ProcessMessages;
end;

procedure TSeRollPanelObject.Roll;
const
  Percent = 1;
var
  RollUp: boolean;
  OwnerObject: TSeSkinObject;
  i: integer;
  TmpValue: integer;
begin
  if Owner = nil then Exit;

  case FRollKind of
    rkLeft, rkRight:
      if Width = FRollValue then
        RollUp := false
      else
        RollUp := true;
    rkTop, rkBottom:
      if Height = FRollValue then
        RollUp := false
      else
        RollUp := true;
  end;

  if RollUp then
  begin
    { RollUp }
    case FRollKind of
      rkLeft: begin
        FOldValue := Width;
        TmpValue := Left + Width;

        for i := 1 to Percent do
        begin
          Width := Width + Round((FRollValue - Width) * (i / Percent));
          Left := TmpValue - Width;
          OwnerUpdate;
        end;
      end;
      rkRight: begin
        FOldValue := Width;

        for i := 1 to Percent do
        begin
          Width := Width + Round((FRollValue - Width) * (i / Percent));
          OwnerUpdate;
        end;
      end;
      rkTop: begin
        FOldValue := Height;
        TmpValue := Top + Height;

        for i := 1 to Percent do
        begin
          Height := Height + Round((FRollValue - Height) * (i / Percent));
          Top := TmpValue - Height;
          OwnerUpdate;
        end;
      end;
      rkBottom: begin
        FOldValue := Height;

        for i := 1 to Percent do
        begin
          Height := Height + Round((FRollValue - Height) * (i / Percent));
          OwnerUpdate;
        end;
      end;
    end;
  end
  else
  begin
    { Restore }
    case FRollKind of
      rkLeft: begin
        TmpValue := Left + Width;

        for i := 1 to Percent do
        begin
          Width := Width - Round((Width - FOldValue) * (i / Percent));
          Left := TmpValue - Width;
          OwnerUpdate;
        end;
      end;
      rkRight: begin
        for i := 1 to Percent do
        begin
          Width := Width - Round((Width - FOldValue) * (i / Percent));
          OwnerUpdate;
        end;
      end;
      rkTop: begin
        TmpValue := Top + Height;

        for i := 1 to Percent do
        begin
          Height := Height - Round((Height - FOldValue) * (i / Percent));
          Top := TmpValue - Height;
          OwnerUpdate;
        end;
      end;
      rkBottom: begin
        for i := 1 to Percent do
        begin
          Height := Height - Round((Height - FOldValue) * (i / Percent));
          OwnerUpdate;
        end;
      end;
    end;
  end;
end;

initialization
  RegisterSkinObject(TSeLinkSkinObject);
  RegisterSkinObject(TSeBitmapSkinObject);
  RegisterSkinObject(TSeFormBitmapSkinObject);
  RegisterSkinObject(TSeSysButtonSkinObject);
  RegisterSkinObject(TSeActiveSkinObject);
  RegisterSkinObject(TSeColorButtonObject);
  RegisterSkinObject(TSeBitmapBoxObject);
  RegisterSkinObject(TSeActiveBitmapBoxObject);
  RegisterSkinObject(TSeButtonBitmapBoxObject);
  RegisterSkinObject(TSeRollPanelObject);
finalization
end.

