{

   This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}
unit UfrmEffect_Layer;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, UfrmEffectBase, ComCtrls, ToolWin,
  GR32_Layers, GR32, StdCtrls, GR32_RangeBars, ExtCtrls, Buttons, Menus,
  clipbrd, UBrowserListView, Spin, Udialog, im_Clipboard, UUndoManage,
  UnViewColorBox;

type
  TfrmEffect_Layer = class(TfrmEffectBase)
    pMlayer: TPopupMenu;
    mnu_layerflatten: TMenuItem;
    mnu_layerdelete: TMenuItem;
    N19: TMenuItem;
    N22: TMenuItem;
    mnu_layerFlipHorz: TMenuItem;
    mnu_layerFlipVert: TMenuItem;
    N21: TMenuItem;
    mnu_layerrotate90: TMenuItem;
    mnu_layerrotate180: TMenuItem;
    mnu_layerrotate270: TMenuItem;
    mnu_layerSet100: TMenuItem;
    bsSkinPanel1: TPanel;
    ScaleCombo: TComboBox;
    Label1: TLabel;
    TrackBar1: TTrackBar;
    N3: TMenuItem;
    N4: TMenuItem;
    Label3: TLabel;
    ColorBox1: TnViewColorBox;
    ListView1: TListView;
    Splitter1: TSplitter;
    stretchfilter: TMenuItem;
    BitBtn9: TBitBtn;
    SpinEdit1: TSpinEdit;
    BitBtn10: TBitBtn;
    N1: TMenuItem;
    N2: TMenuItem;
    N5: TMenuItem;
    N6: TMenuItem;
    N7: TMenuItem;
    N8: TMenuItem;
    N9: TMenuItem;
    N10: TMenuItem;
    N11: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure TrackBar4Change(Sender: TObject);
    procedure mnu_layerflattenClick(Sender: TObject);
    procedure mnu_layerdeleteClick(Sender: TObject);
    procedure mnu_layerFlipHorzClick(Sender: TObject);
    procedure mnu_layerFlipVertClick(Sender: TObject);
    procedure mnu_layerrotate90Click(Sender: TObject);
    procedure mnu_layerrotate180Click(Sender: TObject);
    procedure mnu_layerrotate270Click(Sender: TObject);
    procedure mnu_layerSet100Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure pMlayerPopup(Sender: TObject);
    procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean);
    procedure N3Click(Sender: TObject);
    procedure N4Click(Sender: TObject);
    procedure ListView1DblClick(Sender: TObject);
    procedure Splitter1Moved(Sender: TObject);
    procedure stretchfilterClick(Sender: TObject);
    procedure SpinEdit1Change(Sender: TObject);
    procedure BitBtn9Click(Sender: TObject);
    procedure BitBtn10Click(Sender: TObject);
    procedure N1Click(Sender: TObject);
    procedure N2Click(Sender: TObject);
    procedure N9Click(Sender: TObject);
    procedure N10Click(Sender: TObject);
    procedure N11Click(Sender: TObject);
  private
    { Private declarations }
    RBLayer: TRubberbandLayer;
    FSelection: TPositionedLayer;
    BrowserListView1:TBrowserListView;
    UndoManage1:TUndoManage;

    procedure WndProc(var Message : TMessage); override;
    procedure SetSelection(Value: TPositionedLayer);
    procedure LayerMouseDown(Sender: TObject; Buttons: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure RBResizing(Sender: TObject; const OldLocation: TFloatRect; var NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
    function move_selectlayer(key,pitch:integer):boolean;
    procedure setlayerloaction();
    procedure imagepreview1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);

  public
    { Public declarations }
    property Selection: TPositionedLayer read FSelection write SetSelection;
  end;

const
  STRETCH_FILTER: array [Boolean] of TStretchFilter = (sfNearest, sfLinear);

var
  frmEffect_Layer: TfrmEffect_Layer;

implementation
uses FreeBitmap, FreeImage, FreeUtils, Uconfig, Ufunction, Ufrmmain;

type
  PLayerRec = ^TLayerRec;
  TLayerRec = record
    bitmap:tbitmap32;
    location:tfloatrect;
  end;

var
  copy_LayerRec:PLayerRec;

{$R *.dfm}

procedure TfrmEffect_Layer.WndProc(var Message: TMessage);
var
  idx:integer;
begin
  with Message do
    case msg of
      wm_user+10000:begin
        idx:=config.getvaluebyinteger('layer_listviewselidx',0);
        if (idx>=0) and (idx<=ListView1.Items.Count-1) then begin
          ListView1.Items[idx].Selected:=true;
          ListView1.Items[idx].MakeVisible(true);
        end;
      end;
    end;
  inherited;
end;

procedure TfrmEffect_Layer.FormCreate(Sender: TObject);
begin
  inherited;
  PanelPreView.Align:=alClient;
  imagepreview1.PopupMenu:=pMlayer;
  imagepreview1.ScrollBars.Size:=0;

  self.BorderStyle:=bsSizeable;
  self.BorderIcons:=[biSystemMenu,biMaximize];
  if config.effect_width>=0 then self.Width:=config.effect_width
  else self.Width:=750;
  if config.effect_height>=0 then self.Height:=config.effect_height
  else self.Height:=500;
  if config.effect_max then WindowState:=wsMaximized;

  BrowserListView1:=TBrowserListView.Create(ListView1,40);
  BrowserListView1.TextOutStyle:=tosNoDesc;
  BrowserListView1.TextNameShort:=true;
  BrowserListView1.showhint:=false;
  BrowserListView1.Setthumbspace(22);
  BrowserListView1.Transparent:=true;
  BrowserListView1.Transparentcolor:=clblack;
  BrowserListView1.BrowserDirectory(GetAppDirectory+'layer',handle);

  frmmain.ImageList2.GetBitmap(0, BitBtn9.Glyph);
  frmmain.ImageList2.GetBitmap(10, BitBtn10.Glyph);

  UndoManage1:=TUndoManage.Create(-1,'Layer');
  UndoManage1.maxundocount:=config.c_undomaxcount;

  imagepreview1.OnMouseMove:=imagepreview1MouseMove;
end;

procedure TfrmEffect_Layer.FormDestroy(Sender: TObject);
begin
  inherited;
  UndoManage1.Free;
  config.effect_max:=WindowState=wsMaximized;

  if ListView1.Selected<>nil then
    config.setvaluebyinteger('layer_listviewselidx',ListView1.Selected.Index);

  config.setvaluebyinteger('scaleindex',ScaleCombo.ItemIndex);
  if self.N9.Checked then
    config.setvaluebyinteger('layer_keeyration',1)
  else
    config.setvaluebyinteger('layer_keeyration',0);
  config.setvaluebyinteger('layer_transcolor',self.ColorBox1.Selected);
  config.setvaluebyinteger('layer_listview1width',self.ListView1.Width);
  if stretchfilter.Checked then
    config.setvaluebyinteger('layer_stretchfilter',1)
  else
    config.setvaluebyinteger('layer_stretchfilter',0);
  config.setvaluebyinteger('layer_trans',self.TrackBar1.Position);

  BrowserListView1.Free;

  if WindowState=wsnormal then begin
    config.effect_width:=self.Width;
    config.effect_height:=self.Height;
  end;
end;

procedure TfrmEffect_Layer.LayerMouseDown(Sender: TObject; Buttons: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Sender=nil then exit;
  Selection := TPositionedLayer(Sender);
  if (Buttons = mbLeft) then begin
    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
  end else if (Buttons = mbRight) then begin
    mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
    mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
  end;
end;

procedure TfrmEffect_Layer.SetSelection(Value: TPositionedLayer);
begin
  if Value <> FSelection then
  begin
    if RBLayer <> nil then
    begin
      RBLayer.ChildLayer := nil;
      RBLayer.LayerOptions := LOB_NO_UPDATE;
      imagepreview1.Invalidate;
    end;

    FSelection := Value;

    if Value <> nil then
    begin
      if RBLayer = nil then
      begin
        RBLayer := TRubberBandLayer.Create(imagepreview1.Layers);
        RBLayer.MinHeight := 1;
        RBLayer.MinWidth := 1;
      end
      else RBLayer.BringToFront;
      RBLayer.ChildLayer := Value;
      RBLayer.LayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS or LOB_NO_UPDATE;
      RBLayer.OnResizing := RBResizing;
      if RBLayer.HandleFrame<>clBlack32 then begin
        RBLayer.HandleFrame:=clBlack32;
        RBLayer.HandleFill:=clWhite32;
        RBLayer.Update;
      end;

      if Value is TBitmapLayer then
        with TBitmapLayer(Value) do
        begin
//          Bitmap.MasterAlpha:=TrackBar1.Position;
          TrackBar1.Position:=Bitmap.MasterAlpha;
        end
    end;
  end;
end;


procedure TfrmEffect_Layer.RBResizing(Sender: TObject;
  const OldLocation: TFloatRect; var NewLocation: TFloatRect;
  DragState: TDragState; Shift: TShiftState);
var
  w, h: Single;
  nw, nh: Single;
begin
  if DragState = dsMove then Exit; // we are interested only in scale operations

  if N9.Checked then begin
    w:=TBitmapLayer(Selection).Bitmap.Width;
    h:=TBitmapLayer(Selection).Bitmap.Height;
    nw:=NewLocation.Right-NewLocation.Left;
    nh:=NewLocation.Bottom-NewLocation.Top;
    if nw<=10 then begin
      NewLocation.Right:=NewLocation.Left+10;
      nw:=10;
    end;
    if nh<=10 then begin
      NewLocation.Bottom:=NewLocation.Top+10;
      nh:=10;
    end;

    case DragState of
      dsSizeL,dsSizeBL,
      dsSizeR,dsSizeBR:
        NewLocation.Bottom:=((h*nw) / w)+NewLocation.Top;
      dsSizeTL,dsSizeTR:
        NewLocation.Top:=NewLocation.Bottom-((h*nw) / w);
      dsSizeT,dsSizeB:
        NewLocation.Right:=((w*nh) / h) + NewLocation.Left;
    end;
  end;
end;

procedure TfrmEffect_Layer.TrackBar4Change(Sender: TObject);
begin
  self.SpinEdit1.Value:=TrackBar1.Position;
  if Selection=nil then exit;
  if Selection is TBitmapLayer then
    TBitmapLayer(Selection).Bitmap.MasterAlpha := TrackBar1.Position;
end;

procedure TfrmEffect_Layer.mnu_layerflattenClick(Sender: TObject);
var
  destrect:TRect;
  bitmap:TBitmap;
  bitmap32:TBitmap32;
  W,H:Integer;
  ALayer: TPositionedLayer;
  T: Tbitmap32;
  UndoData1:TUndoData;
begin
  if Selection=nil then exit;

  //add undo
  screen.Cursor:=crHourglass;
  bitmap:=tbitmap.Create;
  try
    imagepreview1.Bitmap.AssignTo24(bitmap);
    UndoData1.bitmap:=bitmap;
    UndoData1.targetrect:=rect(0,0,bitmap.Width,bitmap.Height);
    UndoData1.name:='Layer';
    UndoData1.resized:=true;
    UndoManage1.addundo(bitmap,UndoData1,false);
  finally
    bitmap.Free;
    screen.Cursor:=crdefault;
  end;

  destrect:=MakeRect(TBitmapLayer(Selection).Location);

  W:=imagepreview1.Bitmap.Width;
  H:=imagepreview1.Bitmap.Height;

  if destrect.Left<0 then destrect.Left:=0;
  if destrect.Right>W then destrect.Right:=W;
  if destrect.Top<0 then destrect.Top:=0;
  if destrect.Bottom>H then destrect.Bottom:=H;

  ALayer:=Selection;
  Selection:=nil;
  bitmap32:=TBitmap32.Create;
  try
    bitmap32.SetSize(W, H);
    imagepreview1.PaintTo(bitmap32, Rect(0, 0, W, H));
    imagepreview1.Bitmap.Draw(destrect,destrect,bitmap32);
    Selection:=ALayer;
    mnu_layerdeleteClick(nil);
  finally
    bitmap32.Free;
  end;
end;

procedure TfrmEffect_Layer.mnu_layerdeleteClick(Sender: TObject);
var
  ALayer: TPositionedLayer;
begin
  if Selection <> nil then begin
    ALayer := Selection;
    Selection := nil;
    ALayer.Free;
  end;
end;

procedure TfrmEffect_Layer.mnu_layerFlipHorzClick(Sender: TObject);
begin
  if Selection is TBitmapLayer then
    TBitmapLayer(Selection).Bitmap.FlipHorz;
end;

procedure TfrmEffect_Layer.mnu_layerFlipVertClick(Sender: TObject);
begin
  if Selection is TBitmapLayer then
    TBitmapLayer(Selection).Bitmap.FlipVert;
end;

procedure TfrmEffect_Layer.mnu_layerrotate90Click(Sender: TObject);
var
  R: TFloatRect;
  Cx, Cy, W2, H2: Single;
begin
  if Selection is TBitmapLayer then
  begin
    R := Selection.Location;
    TBitmapLayer(Selection).Bitmap.Rotate90;
    Cx := (R.Left + R.Right) / 2;
    Cy := (R.Top + R.Bottom) / 2;
    W2 := (R.Right - R.Left) / 2;
    H2 := (R.Bottom - R.Top) / 2;
    RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
  end;

end;

procedure TfrmEffect_Layer.mnu_layerrotate180Click(Sender: TObject);
begin
  if Selection is TBitmapLayer then
    TBitmapLayer(Selection).Bitmap.Rotate180;
end;

procedure TfrmEffect_Layer.mnu_layerrotate270Click(Sender: TObject);
var
  R: TFloatRect;
  Cx, Cy, W2, H2: Single;
begin
  if Selection is TBitmapLayer then
  begin
    R := Selection.Location;
    TBitmapLayer(Selection).Bitmap.Rotate270;
    Cx := (R.Left + R.Right) / 2;
    Cy := (R.Top + R.Bottom) / 2;
    W2 := (R.Right - R.Left) / 2;
    H2 := (R.Bottom - R.Top) / 2;
    RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
  end;
end;

procedure TfrmEffect_Layer.mnu_layerSet100Click(Sender: TObject);
var
  L: TFloatRect;
begin
  // resize the layer to the size of its bitmap
  if Selection is TBitmapLayer then
    with RBLayer, TBitmapLayer(Selection).Bitmap do
    begin
      L := Location;
      L.Right := L.Left + Width;
      L.Bottom := L.Top + Height;
      Location := L;
      Changed;
    end;
end;

procedure TfrmEffect_Layer.FormShow(Sender: TObject);
begin
  inherited;
  self.setScaleCombo(ScaleCombo);

  self.N9.Checked:=config.getvaluebyinteger('layer_keeyration',1)=1;
  self.ColorBox1.Selected:=config.getvaluebyinteger('layer_transcolor',clwhite);
  ListView1.Width:=config.getvaluebyinteger('layer_listview1width',135);
  ListView1.Arrange(arAlignTop);
  stretchfilter.Checked:=config.getvaluebyinteger('layer_stretchfilter',1)=1;
  self.TrackBar1.Position:=config.getvaluebyinteger('layer_trans',255);

  labeldisplay1.Left:=10;
  labeldisplay1.Top:=7;

  labeldisplay2.Left:=10;
  labeldisplay2.Top:=labeldisplay1.Top+labeldisplay1.Height+5;
  labeldisplay2.Font.Color:=clblue;
end;

procedure TfrmEffect_Layer.pMlayerPopup(Sender: TObject);
var
  i:integer;
  flag:boolean;
begin
  mnu_layerflatten.Enabled:=Selection<>nil;
  mnu_layerdelete.Enabled:=Selection<>nil;
  mnu_layerSet100.Enabled:=Selection<>nil;
  N3.Enabled:=Selection<>nil;
  N4.Enabled:=Selection<>nil;
  mnu_layerFlipHorz.Enabled:=Selection<>nil;
  mnu_layerFlipVert.Enabled:=Selection<>nil;
  mnu_layerrotate90.Enabled:=Selection<>nil;
  mnu_layerrotate180.Enabled:=Selection<>nil;
  mnu_layerrotate270.Enabled:=Selection<>nil;

  flag:=false;
  for i:=0 to imagepreview1.Layers.Count-1 do
    if imagepreview1.Layers[i] is TBitmapLayer then begin
      flag:=true;
      break;
    end;
  n1.Enabled:=flag;
  n2.Enabled:=UndoManage1.getcount>0;

  n10.Enabled:=Selection<>nil;
  n11.Enabled:=copy_LayerRec<>nil;
end;

function TfrmEffect_Layer.move_selectlayer(key,pitch:integer):boolean;
var
  r:Tfloatrect;
begin
  result:=true;
      if (RBLayer<>nil) then begin
        r:=RBLayer.Location;
        case key of
          vk_left:begin
            r.Left:=r.Left-pitch;
            r.Right:=r.Right-pitch;
          end;
          VK_RIGHT:begin
            r.Left:=r.Left+pitch;
            r.Right:=r.Right+pitch;
          end;
          VK_UP:begin
            r.Top:=r.Top-pitch;
            r.Bottom:=r.Bottom-pitch;
          end;
          VK_DOWN:begin
            r.Top:=r.Top+pitch;
            r.Bottom:=r.Bottom+pitch;
          end;
          else
            result:=false;
        end;
        if result then begin
          RBLayer.Location:=r;
          setlayerloaction();
        end;
      end else
        result:=false;
end;

procedure TfrmEffect_Layer.FormShortCut(var Msg: TWMKey;
  var Handled: Boolean);
begin
  inherited FormShortCut(msg, handled);
  if handled then exit;

  if (GetKeyState(VK_CONTROL)<0) then begin
    Handled:=move_selectlayer(msg.CharCode,config.c_ctrlmovepitch);
  end else if (GetKeyState(VK_SHIFT)<0) then begin
    Handled:=move_selectlayer(msg.CharCode,config.c_shiftmovepitch);
  end else
    Handled:=false;
end;

procedure CromaKey(ABitmap: TBitmap32; TrColor: TColor32);
var
  P: PColor32;
  C: TColor32;
  I: Integer;
begin
  TrColor := TrColor and $00FFFFFF; // erase alpha, (just in case it has some)
  with ABitmap do
  begin
    P := PixelPtr[0, 0];
    for I := 0 to Width * Height - 1 do
    begin
      C := P^ and $00FFFFFF; // get RGB without alpha
      if C = TrColor then // is this pixel "transparent"?
        P^ := C; // write RGB with "transparent" alpha back into the SrcBitmap
      Inc(P); // proceed to the next pixel
    end;
  end;
end;

procedure TfrmEffect_Layer.N3Click(Sender: TObject);
begin
  if Selection is TBitmapLayer then
    with TBitmapLayer(Selection) do begin
      CromaKey(Bitmap,color32(ColorBox1.Selected));
      imagepreview1.Changed;
    end;
end;

procedure TfrmEffect_Layer.N4Click(Sender: TObject);
begin
  if Selection is TBitmapLayer then
    with TBitmapLayer(Selection) do begin
      CromaKey(Bitmap,Bitmap.Pixel[0,0]);
      imagepreview1.Changed;
    end;
end;

procedure TfrmEffect_Layer.ListView1DblClick(Sender: TObject);
var
  PThumbImage1:PThumbImage;
  B: TBitmapLayer;
  P: TPoint;
  W, H: Single;
  FBitmap: TFreeWinBitmap;
  bmp:Tbitmap;
begin
  if ListView1.Selected=nil then exit;
  PThumbImage1:=ListView1.Selected.Data;

      B := TBitmapLayer.Create(imagepreview1.Layers);
      with B do
      try
        Bitmap.DrawMode:=dmBlend;
        Bitmap.LoadFromFile(PThumbImage1.name);
        with imagepreview1.GetViewportRect do
          P := imagepreview1.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));

        W := Bitmap.Width / 2;
        H := Bitmap.Height / 2;

        with imagepreview1.Bitmap do
          Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);

        Scaled := True;
        OnMouseDown := LayerMouseDown;
        Bitmap.StretchFilter:=STRETCH_FILTER[stretchfilter.Checked];
        Bitmap.MasterAlpha:=TrackBar1.Position;
      except
        Free;
        raise;
      end;
      Selection := B;
      imagepreview1.SetFocus;
end;

procedure TfrmEffect_Layer.Splitter1Moved(Sender: TObject);
begin
  ListView1.Arrange(arAlignTop);
end;

procedure TfrmEffect_Layer.stretchfilterClick(Sender: TObject);
var
  i:integer;
begin
  stretchfilter.Checked:=not stretchfilter.Checked;
  for i:=0 to imagepreview1.Layers.Count-1 do
    if imagepreview1.Layers.Items[i] is TBitmapLayer then
      TBitmapLayer(imagepreview1.Layers.Items[i]).Bitmap.StretchFilter:=STRETCH_FILTER[stretchfilter.Checked];
end;

procedure TfrmEffect_Layer.SpinEdit1Change(Sender: TObject);
begin
  if isvalidinteger(SpinEdit1.Text) then TrackBar1.Position:=self.SpinEdit1.Value;
end;

procedure TfrmEffect_Layer.BitBtn9Click(Sender: TObject);
var
  B: TBitmapLayer;
  P: TPoint;
  W, H: Single;
  FBitmap: TFreeWinBitmap;
//  bmp:Tbitmap;
  FreeMemoryIO1:TFreeMemoryIO;
  data:Pbyte;
  SizeInBytes:DWord;
  stream:tmemorystream;
begin
  OpenPictureDialog1.Filter := FIU_GetAllFilters;
  OpenPictureDialog1.InitialDir:=config.lastpath;

     if OpenPictureDialog1.Execute=false then exit;

      config.lastpath:=ExtractFilePath(OpenPictureDialog1.FileName);
      config.c_dialogpreview:=OpenPictureDialog1.ExtraCheckbox.Checked;

      B := TBitmapLayer.Create(imagepreview1.Layers);
      with B do
      try
        FBitmap:=TFreeWinBitmap.Create;
//        bmp:=Tbitmap.Create;
        try
          Bitmap.DrawMode:=dmBlend;
          FBitmap.Load(OpenPictureDialog1.FileName);
//          if (FBitmap.GetImageType=FIT_BITMAP) and FBitmap.IsTransparent then begin
            FreeMemoryIO1:=TFreeMemoryIO.Create();
            try
              FBitmap.SaveToMemory(FIF_BMP,FreeMemoryIO1);
              FreeMemoryIO1.Acquire(data,SizeInBytes);
              stream:=tmemorystream.Create;
              try
                stream.Write(data^,SizeInBytes);
                stream.Position:=0;
                Bitmap.LoadFromStream(stream);
              finally
                stream.Free;
              end;
            finally
              FreeMemoryIO1.Free;
            end;
{          end else begin
            bmp.PixelFormat:=pf24Bit;
            bmp.Width:=FBitmap.GetWidth;
            bmp.Height:=FBitmap.GetHeight;
            FBitmap.Draw(bmp.Canvas.Handle,rect(0,0,bmp.Width,bmp.Height));
            Bitmap.Assign(bmp);
          end;}
        finally
          FBitmap.Free;
//          bmp.Free;
        end;


        with imagepreview1.GetViewportRect do
          P := imagepreview1.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));

        W := Bitmap.Width / 2;
        H := Bitmap.Height / 2;

        with imagepreview1.Bitmap do
          Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);

        Scaled := True;
        OnMouseDown := LayerMouseDown;
        Bitmap.StretchFilter:=STRETCH_FILTER[stretchfilter.Checked];
        Bitmap.MasterAlpha:=TrackBar1.Position;        
      except
        Free;
        raise;
      end;
      Selection := B;
      imagepreview1.SetFocus;
end;

procedure TfrmEffect_Layer.BitBtn10Click(Sender: TObject);
var
  B: TBitmapLayer;
  P: TPoint;
  W, H: Single;
  bmp:Tbitmap;
begin
      B := TBitmapLayer.Create(imagepreview1.Layers);
      with B do
      try
//        PasteBitmap32FromClipboard(bitmap);
        bmp:=tbitmap.Create;
        try
          bmp.PixelFormat:=pf24Bit;
          bmp.LoadFromClipboardFormat(cf_BitMap,
            ClipBoard.GetAsHandle(cf_Bitmap), 0);
          Bitmap.DrawMode := dmBlend;
          Bitmap.Assign(bmp);
        finally
          bmp.Free;
        end;

        with imagepreview1.GetViewportRect do
          P := imagepreview1.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));

        W := Bitmap.Width / 2;
        H := Bitmap.Height / 2;

        with imagepreview1.Bitmap do
          Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);

        Scaled := True;
        OnMouseDown := LayerMouseDown;
        Bitmap.StretchFilter:=STRETCH_FILTER[stretchfilter.Checked];
        Bitmap.MasterAlpha:=TrackBar1.Position;        
      except
        Free;
        raise;
      end;
      Selection := B;
      imagepreview1.SetFocus;
end;

procedure TfrmEffect_Layer.N1Click(Sender: TObject);
var
  bitmap:TBitmap;
  bitmap32:TBitmap32;
  W,H:Integer;
  i:integer;
  flag:boolean;
  UndoData1:TUndoData;
begin
  flag:=false;
  for i:=0 to imagepreview1.Layers.Count-1 do
    if imagepreview1.Layers[i] is TBitmapLayer then begin
      flag:=true;
      break;
    end;
  if flag=false then exit;

  if MessageDlg('모두 이미지에 적용하시겠습니까?',  mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
    exit;

  //add undo
  screen.Cursor:=crHourglass;
  bitmap:=tbitmap.Create;
  try
    imagepreview1.Bitmap.AssignTo24(bitmap);
    UndoData1.bitmap:=bitmap;
    UndoData1.targetrect:=rect(0,0,bitmap.Width,bitmap.Height);
    UndoData1.name:='Layer';
    UndoData1.resized:=true;
    UndoManage1.addundo(bitmap,UndoData1);
  finally
    bitmap.Free;
    screen.Cursor:=crdefault;
  end;

  W:=imagepreview1.Bitmap.Width;
  H:=imagepreview1.Bitmap.Height;

  Selection:=nil;
  bitmap32:=TBitmap32.Create;
  try
    bitmap32.SetSize(W, H);
    imagepreview1.PaintTo(bitmap32, Rect(0, 0, W, H));
    imagepreview1.Bitmap.Assign(bitmap32);
  finally
    bitmap32.Free;
  end;

  for i:=imagepreview1.Layers.Count-1 downto 0 do begin
    if imagepreview1.Layers[i] is TBitmapLayer then
      imagepreview1.Layers[i].Free;
  end;
end;

procedure TfrmEffect_Layer.N2Click(Sender: TObject);
var
  bitmap:TBitmap;
  idx:integer;
begin
  idx:=UndoManage1.getcount-1;
  if idx<0 then exit;
  screen.Cursor:=crHourglass;
  bitmap:=TBitmap.Create;
  try
    if UndoManage1.getundo(bitmap,idx+1) then begin
      imagepreview1.Bitmap.Assign(bitmap);
    end;
  finally
    bitmap.Free;
    screen.Cursor:=crdefault;
  end;
end;

procedure TfrmEffect_Layer.N9Click(Sender: TObject);
begin
  N9.Checked:=not N9.Checked;
end;

procedure TfrmEffect_Layer.setlayerloaction();
var
  r1:trect;
  i:integer;
begin
  if Selection<>nil then begin
    r1:=makerect(TBitmapLayer(Selection).Location);
    labeldisplay1.Caption:=format('레이어 x:%d,y:%d -> x:%d,y:%d (%d,%d)',[
      r1.Left,r1.Top,r1.Right,r1.Bottom,r1.Right-r1.Left,r1.Bottom-r1.Top]);
    labeldisplay2.Caption:='이동단축키: shift,alt+화살표';
  end else begin
    labeldisplay1.Caption:='';
    labeldisplay2.Caption:='';
  end;
end;

procedure TfrmEffect_Layer.N10Click(Sender: TObject);
begin
  if not (Selection is TBitmapLayer) then
    exit;
  if assigned(copy_LayerRec)=false then
    new(copy_LayerRec);
  copy_LayerRec.bitmap:=tbitmap32.Create;
  copy_LayerRec.bitmap.Assign(TBitmapLayer(Selection).Bitmap);
  copy_LayerRec.location:=RBLayer.Location;
end;

procedure TfrmEffect_Layer.N11Click(Sender: TObject);
var
  B: TBitmapLayer;
  r:tfloatrect;
  P,P2: TPoint;
begin
  if assigned(copy_LayerRec)=false then
    exit;

   B := TBitmapLayer.Create(imagepreview1.Layers);
   with B do
    try
      B.Bitmap.Assign(copy_LayerRec.bitmap);

      r:=copy_LayerRec.location;
      with imagepreview1.GetViewportRect do
        P := imagepreview1.ControlToBitmap(Point(Left,Top));
      with imagepreview1.GetViewportRect do
        P2 := imagepreview1.ControlToBitmap(Point(Right,Bottom));

      if r.Left<p.X then r.Left:=p.X;
      if r.Top<p.Y then r.Top:=p.Y;
      if r.Left>p2.X then r.Left:=p.X;
      if r.Top>p2.Y then r.Top:=p.Y;

      r.Right:=r.Left+(copy_LayerRec.location.Right-copy_LayerRec.location.Left);
      r.Bottom:=r.Top+(copy_LayerRec.location.Bottom-copy_LayerRec.location.Top);

      Location:=r;

      Scaled := True;
      OnMouseDown := LayerMouseDown;
      Bitmap.StretchFilter:=STRETCH_FILTER[stretchfilter.Checked];
    except
      Free;
      raise;
    end;
  Selection := B;

  RBLayer.HandleFrame:=color32(clred);
  RBLayer.HandleFill:=color32(clred);
  RBLayer.Update;

  imagepreview1.SetFocus;
end;

procedure TfrmEffect_Layer.imagepreview1MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
  setlayerloaction();
end;

end.
