{
   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 UfrmGifAni;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GIFImage, StdCtrls, ExtCtrls, Spin, Buttons, Menus, ComCtrls,
  GR32_Image;

type

  Pgifdata = ^Tgifdata;
  Tgifdata = record
    idx:integer;
    name:string;
    transparent:boolean;
    left,top:integer;
    delay:integer;
    disposal:integer;
  end;

  TfrmGifAni = class(TForm)
    Panel1: TPanel;
    Button1: TBitBtn;
    Button2: TBitBtn;
    Timer1: TTimer;
    Label3: TLabel;
    MainMenu1: TMainMenu;
    MenuPalette: TMenuItem;
    MenuPaletteNone: TMenuItem;
    MenuPaletteWindows20: TMenuItem;
    MenuPaletteWindows256: TMenuItem;
    MenuPaletteWindowsGray4: TMenuItem;
    MenuPaletteMonochrome: TMenuItem;
    MenuPaletteGrayScale256: TMenuItem;
    MenuPaletteNetscape216: TMenuItem;
    MenuPaletteOptimized: TMenuItem;
    MenuPaletteOptimized8: TMenuItem;
    MenuPaletteOptimized16: TMenuItem;
    MenuPaletteOptimized32: TMenuItem;
    MenuPaletteOptimized64: TMenuItem;
    MenuPaletteOptimized128: TMenuItem;
    MenuPaletteOptimized256: TMenuItem;
    MenuPaletteOptimizedWindows256: TMenuItem;
    MenuDithering: TMenuItem;
    MenuDitheringFloydSteinberg: TMenuItem;
    MenuDitheringStucki: TMenuItem;
    MenuDitheringSierra: TMenuItem;
    MenuDitheringJaJuNi: TMenuItem;
    MenuDitheringSteveArche: TMenuItem;
    MenuDitheringBurkes: TMenuItem;
    MenuDitheringNearest: TMenuItem;
    Button3: TButton;
    N1: TMenuItem;
    Merge1: TMenuItem;
    Crop1: TMenuItem;
    Palette1: TMenuItem;
    TabControl1: TTabControl;
    Splitter1: TSplitter;
    Panel2: TPanel;
    Panel3: TPanel;
    CheckBox1: TCheckBox;
    ImgView321: TImgView32;
    panelgif: TScrollBox;
    ImageAnimate: TImage;
    PopupMenu1: TPopupMenu;
    ListView1: TListView;
    N4: TMenuItem;
    N5: TMenuItem;
    N6: TMenuItem;
    Label5: TLabel;
    SpinEdit2: TSpinEdit;
    Label6: TLabel;
    SpinEdit3: TSpinEdit;
    Label1: TLabel;
    SpinEdit1: TSpinEdit;
    Label2: TLabel;
    Label7: TLabel;
    SpinEdit4: TSpinEdit;
    Label8: TLabel;
    ComboBox1: TComboBox;
    Label9: TLabel;
    Panel4: TPanel;
    Label4: TLabel;
    CheckBox2: TCheckBox;
    Label10: TLabel;
    ComboBox2: TComboBox;
    Label11: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure MenuPaletteNoneClick(Sender: TObject);
    procedure MenuPaletteOptimized8Click(Sender: TObject);
    procedure MenuDitheringFloydSteinbergClick(Sender: TObject);
    procedure MenuPaletteOptimizedClick(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Merge1Click(Sender: TObject);
    procedure TabControl1Change(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure CheckBox2Click(Sender: TObject);
    procedure ImgView321Resize(Sender: TObject);
    procedure ListView1DragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure ListView1DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure N4Click(Sender: TObject);
    procedure N6Click(Sender: TObject);
    procedure TabControl1GetImageIndex(Sender: TObject; TabIndex: Integer;
      var ImageIndex: Integer);
    procedure PopupMenu1Popup(Sender: TObject);
    procedure SpinEdit4Change(Sender: TObject);
    procedure ComboBox2Change(Sender: TObject);
  private
    { Private declarations }
    ReductionBits:integer;
    procedure make_gifimage();
    procedure fittoscreen();
  public
    { Public declarations }
    imglist:tlist;
    giflist:tlist;
  end;

var
  frmGifAni: TfrmGifAni;

implementation
uses Ufrmmain, Udialog, Ufunction, Uconfig;
{$R *.dfm}

procedure TfrmGifAni.FormCreate(Sender: TObject);
var
  i:integer;
  ColorReduction: TColorReduction;
  DitherMode: TDitherMode;
begin
  imglist:=tlist.Create;
  giflist:=tlist.Create;

  ImageAnimate.Left:=0;
  ImageAnimate.Top:=0;
  panelgif.Align:=alclient;

  panelgif.DoubleBuffered:=true;
  panelgif.Color:=config.c_defaultviewcolor;

  TabControl1.Align:=alclient;
  TabControl1.TabIndex:=0;
  TabControl1Change(nil);

  ImgView321.Color:=config.c_defaultviewcolor;
  label4.Caption:='';

  frmmain.ImageList2.GetBitmap(5, Button1.Glyph);
  frmmain.ImageList2.GetBitmap(0, Button2.Glyph);

  self.Left:=config.getvaluebyinteger('gifani_left',10);
  self.Top:=config.getvaluebyinteger('gifani_top',10);
  self.Width:=config.getvaluebyinteger('gifani_width',600);
  self.Height:=config.getvaluebyinteger('gifani_height',500);
  if config.getvaluebyinteger('gifani_maxwindow',0)=1 then
    self.WindowState:=wsMaximized;

  i:=config.getvaluebyinteger('gifani_ColorReduction',integer(rmQuantize));
  ColorReduction:=TColorReduction(i);

      if (ColorReduction=rmNetscape) then
        MenuPaletteNetscape216.Checked:=true
      else if (ColorReduction=rmMonochrome) then
        MenuPaletteMonochrome.Checked:=true
      else if (ColorReduction=rmGrayScale) then
        MenuPaletteGrayScale256.Checked:=true
      else if (ColorReduction=rmWindowsGray) then
        MenuPaletteWindowsGray4.Checked:=true
      else if (ColorReduction=rmWindows20) then
        MenuPaletteWindows20.Checked:=true
      else if (ColorReduction=rmWindows256) then
        MenuPaletteWindows256.Checked:=true
      else if (ColorReduction=rmQuantize) then
        MenuPaletteOptimized.Checked:=true
      else if (ColorReduction=rmQuantizeWindows) then
        MenuPaletteOptimizedWindows256.Checked:=true
      else
        MenuPaletteNone.Checked:=true;

  i:=config.getvaluebyinteger('gifani_DitherMode',integer(dmNearest));
  DitherMode:=TDitherMode(i);

      if (DitherMode=dmFloydSteinberg) then
        MenuDitheringFloydSteinberg.Checked:=true
      else if (DitherMode = dmStucki) then
        MenuDitheringStucki.Checked:=true
      else if (DitherMode = dmSierra) then
        MenuDitheringSierra.Checked:=true
      else if (DitherMode = dmJaJuNi) then
        MenuDitheringJaJuNi.Checked:=true
      else if (DitherMode = dmSteveArche) then
        MenuDitheringSteveArche.Checked:=true
      else if (DitherMode = dmBurkes) then
        MenuDitheringBurkes.Checked:=true
      else if (DitherMode = dmNearest) then
        MenuDitheringNearest.Checked:=true;

  ReductionBits:=config.getvaluebyinteger('gifani_ReductionBits',8);

  merge1.Checked:=config.getvaluebyinteger('gifani_merge',0)=1;
  crop1.Checked:=config.getvaluebyinteger('gifani_crop',0)=1;
  palette1.Checked:=config.getvaluebyinteger('gifani_palette',0)=1;
  self.ListView1.Width:=config.getvaluebyinteger('gifani_treeview1',190);
  self.CheckBox2.Checked:=config.getvaluebyinteger('gifani_fittoscreen',1)=1;
  SpinEdit4.Value:=config.getvaluebyinteger('gifani_delay',200);
  self.ComboBox2.ItemIndex:=config.getvaluebyinteger('gifani_disposal',0);
end;

procedure TfrmGifAni.FormDestroy(Sender: TObject);
var
  ColorReduction: TColorReduction;
  DitherMode: TDitherMode;
  i:integer;
begin
      if (MenuPaletteNetscape216.Checked) then
        ColorReduction := rmNetscape
      else if (MenuPaletteMonochrome.Checked) then
        ColorReduction := rmMonochrome
      else if (MenuPaletteGrayScale256.Checked) then
        ColorReduction := rmGrayScale
      else if (MenuPaletteWindowsGray4.Checked) then
        ColorReduction := rmWindowsGray
      else if (MenuPaletteWindows20.Checked) then
        ColorReduction := rmWindows20
      else if (MenuPaletteWindows256.Checked) then
        ColorReduction := rmWindows256
      else if (MenuPaletteOptimized.Checked) then
        ColorReduction := rmQuantize
      else if (MenuPaletteOptimizedWindows256.Checked) then
        ColorReduction := rmQuantizeWindows
      else
        ColorReduction := rmNone;
  config.setvaluebyinteger('gifani_ColorReduction',integer(ColorReduction));

      if (MenuDitheringFloydSteinberg.Checked) then
        DitherMode := dmFloydSteinberg
      else if (MenuDitheringStucki.Checked) then
        DitherMode := dmStucki
      else if (MenuDitheringSierra.Checked) then
        DitherMode := dmSierra
      else if (MenuDitheringJaJuNi.Checked) then
        DitherMode := dmJaJuNi
      else if (MenuDitheringSteveArche.Checked) then
        DitherMode := dmSteveArche
      else if (MenuDitheringBurkes.Checked) then
        DitherMode := dmBurkes
      else if (MenuDitheringNearest.Checked) then
        DitherMode := dmNearest;
  config.setvaluebyinteger('gifani_DitherMode',integer(DitherMode));

  config.setvaluebyinteger('gifani_ReductionBits',ReductionBits);
  config.setvaluebyinteger('gifani_merge',integer(merge1.Checked));
  config.setvaluebyinteger('gifani_crop',integer(merge1.Checked));
  config.setvaluebyinteger('gifani_palette',integer(merge1.Checked));
  config.setvaluebyinteger('gifani_delay',SpinEdit4.Value);
  config.setvaluebyinteger('gifani_disposal',self.ComboBox2.ItemIndex);

  config.setvaluebyinteger('gifani_treeview1',self.ListView1.Width);
  config.setvaluebyinteger('gifani_fittoscreen',integer(self.CheckBox2.Checked));

  if WindowState=wsNormal then begin
    config.setvaluebyinteger('gifani_left',self.Left);
    config.setvaluebyinteger('gifani_top',self.Top);
    config.setvaluebyinteger('gifani_width',self.Width);
    config.setvaluebyinteger('gifani_height',self.Height);
    config.setvaluebyinteger('gifani_maxwindow',0);
  end else if WindowState=wsMaximized then
    config.setvaluebyinteger('gifani_maxwindow',1);

  imglist.Free;
  for i:=0 to giflist.Count-1 do
    dispose(Pgifdata(giflist.Items[i]));
  giflist.Free;
end;

procedure TfrmGifAni.make_gifimage();
var
  GIF			: TGIFImage;
  i			: integer;
  OptimizeOptions	: TGIFOptimizeOptions;
  PWorkImage1:PWorkImage;
  PixelFormat:TPixelFormat;
  bitmap:tbitmap;
  ms:tmemorystream;
  ColorReduction: TColorReduction;
  DitherMode: TDitherMode;
  gifdata: Pgifdata;

  function TransparentIndex(GIF: TGIFSubImage): byte;
  begin
    // Use the lower left pixel as the transparent color
    Result := GIF.Pixels[0, GIF.Height-1];
  end;

  function AddBitmap(GIF: TGIFImage; Source: TGraphic): integer;
  var
    Ext			: TGIFGraphicControlExtension;
    LoopExt		: TGIFAppExtNSLoop;
  begin
    // Preview the image being added (for user feedback)
    ImageAnimate.Picture.Assign(Source);
    ImageAnimate.Update;

    // Add the source image to the animation
    Result := GIF.Add(Source);
    // Netscape Loop extension must be the first extension in the first frame!
    if (Result = 0) then
    begin
      LoopExt := TGIFAppExtNSLoop.Create(GIF.Images[Result]);
      LoopExt.Loops := 0; // Number of loops (0 = forever)
      GIF.Images[Result].Extensions.Add(LoopExt);
    end;
    GIF.Images[Result].Left:=gifdata.left;
    GIF.Images[Result].Top:=gifdata.top;

    // Add Graphic Control Extension
    Ext := TGIFGraphicControlExtension.Create(GIF.Images[Result]);
    Ext.Delay := gifdata.delay div 10;
    Ext.Disposal:= TDisposalMethod(gifdata.disposal);
    if (gifdata.transparent) then
    begin
      Ext.Transparent := True;
      Ext.TransparentColorIndex := TransparentIndex(GIF.Images[Result]);
    end;
    GIF.Images[Result].Extensions.Add(Ext);
  end;

begin
  if ListView1.Items.Count=0 then
    exit;
  Screen.Cursor := crHourGlass;
  try
    GIF := TGIFImage.Create;
    try

      if (MenuPaletteNetscape216.Checked) then
        ColorReduction := rmNetscape
      else if (MenuPaletteMonochrome.Checked) then
        ColorReduction := rmMonochrome
      else if (MenuPaletteGrayScale256.Checked) then
        ColorReduction := rmGrayScale
      else if (MenuPaletteWindowsGray4.Checked) then
        ColorReduction := rmWindowsGray
      else if (MenuPaletteWindows20.Checked) then
        ColorReduction := rmWindows20
      else if (MenuPaletteWindows256.Checked) then
        ColorReduction := rmWindows256
      else if (MenuPaletteOptimized.Checked) then
        ColorReduction := rmQuantize
      else if (MenuPaletteOptimizedWindows256.Checked) then
        ColorReduction := rmQuantizeWindows
      else
        ColorReduction := rmNone;

      if (MenuDitheringFloydSteinberg.Checked) then
        DitherMode := dmFloydSteinberg
      else if (MenuDitheringStucki.Checked) then
        DitherMode := dmStucki
      else if (MenuDitheringSierra.Checked) then
        DitherMode := dmSierra
      else if (MenuDitheringJaJuNi.Checked) then
        DitherMode := dmJaJuNi
      else if (MenuDitheringSteveArche.Checked) then
        DitherMode := dmSteveArche
      else if (MenuDitheringBurkes.Checked) then
        DitherMode := dmBurkes
      else if (MenuDitheringNearest.Checked) then
        DitherMode := dmNearest;

      for i:=0 to ListView1.Items.Count-1 do begin
        gifdata:=Pgifdata(ListView1.Items[i].Data);
        PWorkImage1:=PWorkImage(imglist.Items[gifdata.idx]);
        PixelFormat:=GetPixelFormat(PWorkImage1.bitmap);
        if PixelFormat=pf24bit then begin
          bitmap:=ReduceColors(PWorkImage1.bitmap, ColorReduction, DitherMode, ReductionBits, 0);
          gifdata:=Pgifdata(giflist.Items[i]);
          AddBitmap(GIF, bitmap);
          bitmap.Free;
        end else
          AddBitmap(GIF, PWorkImage1.bitmap);
      end;

{
      for i := 0 to self.imglist.Count-1 do begin
        PWorkImage1:=PWorkImage(imglist.Items[i]);
        PixelFormat:=GetPixelFormat(PWorkImage1.bitmap);
         if PixelFormat=pf24bit then begin
           bitmap:=ReduceColors(PWorkImage1.bitmap, ColorReduction, DitherMode, ReductionBits, 0);
           gifdata:=Pgifdata(giflist.Items[i]);
           AddBitmap(GIF, bitmap, gifdata.transparent);
           bitmap.Free;
         end else
           AddBitmap(GIF, PWorkImage1.bitmap, false);
      end;
}
      // Optimize Color map...
      if (Palette1.Checked) then
        GIF.OptimizeColorMap;

      // Optimize GIF frames...
      OptimizeOptions := [];
      if (Merge1.Checked) then
        include(OptimizeOptions, ooMerge);
      if (Crop1.Checked) then
        include(OptimizeOptions, ooCrop);
      if (OptimizeOptions <> []) then
        GIF.Optimize(OptimizeOptions, rmNone, dmNearest, 0);

      // Display the animation
      ms:=tmemorystream.Create;
      try
        gif.SaveToStream(ms);
        Label3.Caption:=format('저장될 크기: %s byte (%s)',[
           FormatFloat('#,###,###',ms.Size),ConvertSize(inttostr(ms.Size))]);
      finally
        ms.Free;
      end;
      ImageAnimate.Picture.Assign(GIF);
    finally
      GIF.Free;
    end;
  finally
    Screen.Cursor := crDefault;
  end;
end;

procedure TfrmGifAni.Button1Click(Sender: TObject);
begin
  ImageAnimate.Picture.Assign(nil);
  make_gifimage();
  TabControl1.TabIndex:=0;
  TabControl1Change(nil);
end;

procedure TfrmGifAni.Button2Click(Sender: TObject);
var
  SaveDialog1:TmySavePictureDialog;
  s:string;
label reopendialog;
begin
reopendialog:
  SaveDialog1:=TmySavePictureDialog.Create(self);
  SaveDialog1.Filter:='GIF파일|*.gif|모든파일|*.*';
  SaveDialog1.FileName:=config.getvaluebystring('gifani_filename','');
  SaveDialog1.enablesaveopt:=false;
  try
    if SaveDialog1.Execute=false then exit;
    s:=sysutils.ChangeFileExt(SaveDialog1.FileName,'.gif');
  finally
    SaveDialog1.Free;
  end;
  if sysutils.FileExists(s) then begin
    if MessageDlg(format('"%s" 파일이 이미 존재합니다.',[ExtractFileName(s)])+#13#10+'덮어 씌우시겠습니까?',
        mtConfirmation, [mbYes, mbNo], 0)<>mrYes then
      goto reopendialog;
  end;
  config.setvaluebystring('gifani_filename',s);
  ImageAnimate.Picture.SaveToFile(s);
end;

procedure TfrmGifAni.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled:=false;
  make_gifimage();
  if ListView1.Items.Count>0 then
    ListView1.Items[0].Selected:=true;
end;

procedure TfrmGifAni.FormShow(Sender: TObject);
var
  i:integer;
  gifdata:Pgifdata;
  listitem:tlistitem;
  s:string;
begin
  for i:=0 to giflist.Count-1 do begin
    gifdata:=Pgifdata(giflist.Items[i]);
    listitem:=ListView1.Items.Add;
    s:=ExtractFileName(gifdata.name);
    if s='' then s:='이름없음';
    listitem.Caption:=s;
    listitem.Data:=gifdata;
    listitem.ImageIndex:=12;
  end;
  timer1.Enabled:=true;
end;

procedure TfrmGifAni.MenuPaletteNoneClick(Sender: TObject);
begin
  TMenuItem(Sender).Checked := True;
end;

procedure TfrmGifAni.MenuPaletteOptimized8Click(Sender: TObject);
begin
  ReductionBits:=TMenuItem(Sender).Tag;
  TMenuItem(Sender).Checked := True;
end;

procedure TfrmGifAni.MenuDitheringFloydSteinbergClick(Sender: TObject);
begin
  TMenuItem(Sender).Checked := True;
end;

procedure TfrmGifAni.MenuPaletteOptimizedClick(Sender: TObject);
var
  i:integer;
begin
  TMenuItem(Sender).Checked := True;
  for i:=0 to MenuPaletteOptimized.Count-1 do
    if MenuPaletteOptimized.Items[i].Tag=ReductionBits then begin
      MenuPaletteOptimized.Items[i].Checked:=true;
      break;
    end;
end;

procedure TfrmGifAni.Button3Click(Sender: TObject);
begin
  SpinEdit4.Value:=200;
  ComboBox2.ItemIndex:=0;
  MenuPaletteOptimized.Checked:=true;
  MenuDitheringNearest.Checked:=true;
  ReductionBits:=8;
  merge1.Checked:=false;
  crop1.Checked:=false;
  palette1.Checked:=false;
end;

procedure TfrmGifAni.Merge1Click(Sender: TObject);
begin
  TMenuItem(Sender).Checked:=not TMenuItem(Sender).Checked;
end;

procedure TfrmGifAni.TabControl1Change(Sender: TObject);
begin
  case TabControl1.TabIndex of
    0:begin
      self.ListView1.Visible:=false;
      Panel2.Visible:=false;
      self.Splitter1.Visible:=false;
      self.panelgif.Visible:=true;
    end;
    1:begin
      self.ListView1.Visible:=true;
      Panel2.Visible:=true;
      self.Splitter1.Left:=ListView1.Left+ListView1.Width+50;
      self.Splitter1.Visible:=true;
      self.panelgif.Visible:=false;
    end;
  end;
end;

procedure TfrmGifAni.fittoscreen();
var
  ratio:Single;
  w,h,gap:integer;
begin
  gap:=GetSystemMetrics(SM_CYHSCROLL)+17;
  w:=imgview321.Bitmap.Width;
  h:=imgview321.Bitmap.Height;
  if ((imgview321.Width-gap)>=w) and ((imgview321.Height-gap)>=h) then
    ratio:=1
  else begin
    ratio:=(imgview321.Width-gap) / w;
    if (imgview321.Height-gap) < (ratio*h) then begin
      ratio:=(imgview321.Height-gap) / h;
    end;
  end;
  imgview321.Scale:=ratio;
end;

procedure TfrmGifAni.CheckBox2Click(Sender: TObject);
begin
  if self.CheckBox2.Checked then
    fittoscreen()
  else
    imgview321.Scale:=1;
end;

procedure TfrmGifAni.ImgView321Resize(Sender: TObject);
begin
  if self.CheckBox2.Checked then
    fittoscreen()
  else
    imgview321.Scale:=1;
end;

procedure TfrmGifAni.ListView1DragDrop(Sender, Source: TObject; X,
  Y: Integer);
var
  listitem:tlistitem;
  i,j:integer;
  list:tlist;
  gifdata:Pgifdata;
  s:string;
begin
  listitem:=ListView1.GetItemAt(X,Y);
  if listitem=nil then exit;
  if ListView1.SelCount=0 then exit;

  list:=tlist.Create;
  try
   for i:=0 to listview1.Items.Count-1 do begin
     if listview1.Items[i].Selected then
       list.Add(listview1.Items[i].Data);
   end;
   listview1.DeleteSelected;

   j:=listitem.Index;
   for i:=list.Count-1 downto 0 do begin
     gifdata:=Pgifdata(list.Items[i]);
     listitem:=listview1.Items.Insert(j);
     s:=ExtractFileName(gifdata.name);
     if s='' then s:='이름없음';
     listitem.Caption:=s;
     listitem.Data:=gifdata;
     listitem.ImageIndex:=12;
     listitem.Selected:=true;
     if i=0 then listitem.Focused:=true;
   end;
  finally
    list.Free;
  end;
end;

procedure TfrmGifAni.ListView1DragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
var
  listitem:tlistitem;
begin
  accept:=false;
  listitem:=ListView1.GetItemAt(X,Y);
  if (listitem=nil) or (listitem.Selected) then exit;
  accept:=true;
end;

procedure TfrmGifAni.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
var
  gifdata:Pgifdata;
  PWorkImage1:PWorkImage;
begin
  if Selected=false then exit;
  if ListView1.SelCount>1 then exit;
  if ListView1.Selected=nil then exit;

  gifdata:=Pgifdata(ListView1.Selected.Data);
  self.CheckBox1.Checked:=gifdata.transparent;
  self.SpinEdit2.Value:=gifdata.left;
  self.SpinEdit3.Value:=gifdata.top;
  self.SpinEdit1.Value:=gifdata.delay;
  self.ComboBox1.ItemIndex:=gifdata.disposal;

  PWorkImage1:=PWorkImage(imglist.Items[gifdata.idx]);
  ImgView321.Bitmap.Assign(PWorkImage1.bitmap);
  if self.CheckBox2.Checked then
    fittoscreen()
  else
    imgview321.Scale:=1;

  label4.Caption:=format('크기: %d X %d',[PWorkImage1.bitmap.Width, PWorkImage1.bitmap.Height]);
end;

procedure TfrmGifAni.N4Click(Sender: TObject);
var
  gifdata:Pgifdata;
  i:integer;
  listitem:Tlistitem;
  s:string;
begin
  if listview1.SelCount<>1 then exit;
  if (Sender as tmenuitem).Tag=0 then begin
    i:=listview1.Selected.Index-1;
    if i<0 then exit;
  end else begin
    i:=listview1.Selected.Index+1;
    if i>listview1.Items.Count-1 then exit;
  end;
  gifdata:=Pgifdata(listview1.Selected.Data);
  listview1.Selected.Delete;

  listitem:=listview1.Items.Insert(i);
  s:=ExtractFileName(gifdata.name);
  if s='' then s:='이름없음';
  listitem.Caption:=s;
  listitem.Data:=gifdata;
  listitem.ImageIndex:=12;

  listitem.Selected:=true;
  listitem.Focused:=true;

  listitem.MakeVisible(false);
end;

procedure TfrmGifAni.N6Click(Sender: TObject);
begin
  listview1.DeleteSelected;
  self.ImgView321.Bitmap.Delete;
end;

procedure TfrmGifAni.TabControl1GetImageIndex(Sender: TObject;
  TabIndex: Integer; var ImageIndex: Integer);
begin
  case TabIndex of
    0: ImageIndex:=13;
    1: ImageIndex:=11;
  end;
end;

procedure TfrmGifAni.PopupMenu1Popup(Sender: TObject);
var
  c,t:integer;
begin
  c:=ListView1.SelCount;
  t:=ListView1.Items.Count;
  N4.Enabled:=c=1;
  N5.Enabled:=c=1;
  N6.Enabled:=c>0;
end;

procedure TfrmGifAni.CheckBox1Click(Sender: TObject);
var
  gifdata:Pgifdata;
  i:integer;

  procedure setdata;
  begin
    case (sender as TComponent).Tag of
     0: gifdata.left:=self.SpinEdit2.Value;
     1: gifdata.top:=self.SpinEdit3.Value;
     2: gifdata.transparent:=CheckBox1.Checked;
     3: gifdata.delay:=self.SpinEdit1.Value;
     4: gifdata.disposal:=self.ComboBox1.ItemIndex;
    end;
  end;
begin
  if ListView1.SelCount=0 then exit;

  if ListView1.SelCount=1 then begin
    gifdata:=Pgifdata(ListView1.Selected.Data);
    setdata;
  end else begin
    for i:=0 to ListView1.Items.Count-1 do begin
      if ListView1.Items[i].Selected then begin
        gifdata:=Pgifdata(ListView1.Items[i].Data);
        setdata;
      end;
    end;
  end;
end;

procedure TfrmGifAni.SpinEdit4Change(Sender: TObject);
var
  gifdata:Pgifdata;
  i:integer;
begin
  for i:=0 to ListView1.Items.Count-1 do begin
    gifdata:=Pgifdata(ListView1.Items[i].Data);
    gifdata.delay:=self.SpinEdit4.Value;
  end;
  SpinEdit1.Value:=SpinEdit4.Value;
end;

procedure TfrmGifAni.ComboBox2Change(Sender: TObject);
var
  gifdata:Pgifdata;
  i:integer;
begin
  for i:=0 to ListView1.Items.Count-1 do begin
    gifdata:=Pgifdata(ListView1.Items[i].Data);
    gifdata.disposal:=self.ComboBox2.ItemIndex;
  end;
  ComboBox1.ItemIndex:=ComboBox2.ItemIndex;
end;

end.
