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

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls, GR32_Image, GR32, GR32_Layers,
  BusinessSkinForm, GR32_Resamplers, gr32_transforms;

type
  TfrmEffectBase = class(TForm)
    PanelBottom: TPanel;
    PanelPreView: TPanel;
    imagepreview1: TImgView32;
    panelbtn: TPanel;
    BitBtn2: TBitBtn;
    BitBtn1: TBitBtn;
    applyselect: TComboBox;
    labeldisplay1: TLabel;
    labeldisplay2: TLabel;
    labeldisplay3: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure BitBtn2Click(Sender: TObject);
    procedure imagepreview1MouseWheelDown(Sender: TObject;
      Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
    procedure imagepreview1MouseWheelUp(Sender: TObject;
      Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
    procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean);
    procedure imagepreview1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure imagepreview1Resize(Sender: TObject);
  private
    { Private declarations }
    OldMousePos: TPoint;
    MouseDragging: Boolean;
    isfittoscreen:boolean;

    procedure fittoscreen();
  protected
    procedure Resample(Src,Dst: TBitmap32; X,Y: Integer; Filter:TStretchFilter);
    procedure imagepreview1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); virtual;
    procedure imagepreview1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); virtual;
    procedure imagepreview1MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer; Layer: TCustomLayer);
  public
    { Public declarations }
    org_bitmap32:TBitmap32;
    thumb_bitmap32:TBitmap32;
    thumbratio:extended;
    imagepreview1_mouse:boolean;
    fScaleCombo:TComboBox;

    procedure imagepreview1_scale;
    procedure ok_select; virtual;
    procedure make_thumbimage;
    procedure ScaleCombo2Change(Sender: TObject);
    procedure setScaleCombo(ScaleCombo:TComboBox);
  end;

var
  frmEffectBase: TfrmEffectBase;

implementation
uses Ufrmmain, Uconfig;

{$R *.dfm}

procedure TfrmEffectBase.FormCreate(Sender: TObject);
begin
  fScaleCombo:=nil;
  imagepreview1_mouse:=true;
  imagepreview1.Color:=config.c_defaultviewcolor;
    
  org_bitmap32:=TBitmap32.Create;
  thumb_bitmap32:=TBitmap32.Create;
  imagepreview1.OnMouseDown:=imagepreview1MouseDown;
  imagepreview1.OnMouseUp:=imagepreview1MouseUp;
  imagepreview1.OnMouseMove:=imagepreview1MouseMove;
  imagepreview1.blocklayermousedown:=true;
  imagepreview1.TabStop:=true;

  if config.effect_left>=0 then
    self.Left:=config.effect_left
  else
    self.Left:=frmmain.Left+((frmmain.Width div 2)-(700 div 2));
  if config.effect_top>=0 then
    self.Top:=config.effect_top
  else
    self.Top:=frmmain.Top+((frmmain.Height div 2)-(500 div 2));

  labeldisplay1.Caption:='';
  labeldisplay2.Caption:='';
  labeldisplay3.Caption:='';
end;

procedure TfrmEffectBase.FormDestroy(Sender: TObject);
begin
  org_bitmap32.Free;
  thumb_bitmap32.Free;

  config.effect_left:=self.Left;
  config.effect_top:=self.Top;
end;

procedure TfrmEffectBase.FormShow(Sender: TObject);
begin
  imagepreview1.Bitmap.Assign(org_bitmap32);
  BitBtn2.SetFocus;
end;

procedure TfrmEffectBase.Resample(Src,Dst: TBitmap32; X,Y: Integer; Filter:TStretchFilter);
var
  RectS: TRect;
  RectD: TRect;
  DstClipW,DstClipH:Trect;
  resampler:TCustomResampler;
Begin
  //(NearestFilter, LinearFilter,SplineFilter, LanczosFilter, MitchellFilter);
  RectS.Top := 0;
  RectS.Left := 0;
  RectS.Right := src.Width;
  RectS.Bottom := src.Height;
  RectD.Top := 0;
  RectD.Left := 0;
  RectD.Right := X;
  RectD.Bottom := Y;
  //DstClipW := DstClip.Right - DstClip.Left;
  //DstClipH := DstClip.Bottom - DstClip.Top;
  Dst.Clear(clGray32);
  Dst.Width:=X;
  Dst.Height:=Y;
  Src.DrawTo(dst,RectD,RectS);

  case Filter of
    sfNearest:resampler:=TNearestResampler.Create;
    sfDraft:resampler:=TDraftResampler.Create;
    sfLinear:resampler:=TLinearResampler.Create;
  else
    resampler:=TKernelResampler.Create;
    with resampler as TKernelResampler do
      case Filter of
        sfCosine: Kernel := TCosineKernel.Create;
        sfSpline: Kernel := TSplineKernel.Create;
        sfLanczos: Kernel := TLanczosKernel.Create;
        sfMitchell: Kernel := TMitchellKernel.Create;
      end;
  end;
  try
    StretchTransfer(Dst, RectD, RectD, Src, RectS, resampler, dmCustom, nil);
  finally
    resampler.Free;
  end;
end;

procedure TfrmEffectBase.make_thumbimage;
var
  w,h:integer;
  NewWidth,NewHeight:integer;
  thumbsize:integer;
begin
  BitBtn2.SetFocus;

  w:=org_bitmap32.Width;
  h:=org_bitmap32.Height;

  if w > h then begin
    thumbsize:=imagepreview1.Width-20;
    NewWidth:=thumbsize;
    NewHeight:=Round((thumbsize) * h / w);
  end else begin
    thumbsize:=imagepreview1.Height-20;
    NewWidth:=Round((thumbsize) * w / h);
    NewHeight:=thumbsize;
  end;
  if NewWidth > w then NewWidth:=w;
  if NewHeight > h then NewHeight:=h;
  if NewWidth<=0 then NewWidth:=1;
  if NewHeight<=0 then NewHeight:=1;

  Resample(org_bitmap32,thumb_bitmap32,NewWidth,NewHeight,sfLanczos);

  thumbratio:=thumb_bitmap32.Width / org_bitmap32.Width;  
end;

procedure TfrmEffectBase.imagepreview1_scale;
var
  ratio:Single;
  w,h:integer;
begin
  w:=imagepreview1.Bitmap.Width;
  h:=imagepreview1.Bitmap.Height;
  ratio:=imagepreview1.Width / (w+50);
  if imagepreview1.Height < (ratio*h) then begin
    ratio:=imagepreview1.Height / (h+50);
  end;
  imagepreview1.Scale:=ratio;
  isfittoscreen:=false;
end;

procedure TfrmEffectBase.ok_select;
begin
  inherited;
end;

procedure TfrmEffectBase.BitBtn2Click(Sender: TObject);
var
  s:String;
begin
  if applyselect.Visible then begin
    if applyselect.ItemIndex=1 then s:='리스트에 선택된 이미지들에 적용하시겠습니까?'
    else if applyselect.ItemIndex=2 then s:='리스트에 모든 이미지에 적용하시겠습니까?';
    if s<>'' then
      if MessageDlg(s,  mtConfirmation, [mbYes, mbNo], 0)<>mryes then
        exit;
  end;
  ok_select;
  if (applyselect.Visible=false) or (applyselect.Visible and (applyselect.ItemIndex=0)) then begin
    org_bitmap32.Assign(imagepreview1.Bitmap);
    self.ModalResult:=mrok;
  end;
end;

procedure TfrmEffectBase.imagepreview1MouseWheelDown(Sender: TObject;
  Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
  if (imagepreview1.Bitmap.Height*imagepreview1.Scale) > imagepreview1.ClientHeight then
    imagepreview1.Scroll(0,50)
  else
    imagepreview1.Scroll(50,0);
end;

procedure TfrmEffectBase.imagepreview1MouseWheelUp(Sender: TObject;
  Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
begin
  if (imagepreview1.Bitmap.Height*imagepreview1.Scale) > imagepreview1.ClientHeight then
    imagepreview1.Scroll(0,-50)
  else
    imagepreview1.Scroll(-50,0);
end;

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

procedure TfrmEffectBase.ScaleCombo2Change(Sender: TObject);
var
  S: string;
  I: Integer;
  combobox:Tcombobox;
begin
  combobox:=Tcombobox(sender);
  if combobox.ItemIndex=0 then begin
    fittoscreen();
  end else begin
    S := combobox.Text;
    S := StringReplace(S, '%', '', [rfReplaceAll]);
    S := StringReplace(S, ' ', '', [rfReplaceAll]);
    if S = '' then Exit;
    I := StrToIntDef(S, -1);
    if (I < 1) or (I > 2000) then I := Round(imagepreview1.Scale * 100)
    else imagepreview1.Scale:=I / 100;
    isfittoscreen:=false;
  end;
end;

procedure TfrmEffectBase.imagepreview1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
  Layer: TCustomLayer);
begin
  if imagepreview1_mouse=false then exit;
//  imagepreview1.SetFocus; //imagview tabstop=true 인 경우 필요없음
  if Button=mbLeft then begin
    if imagepreview1.ScrollBars.Size>=0 then begin
      OldMousePos := Point(X, Y);
      MouseDragging := True;
      imagepreview1.Cursor := crSizeAll;
    end;
  end;
end;

procedure TfrmEffectBase.imagepreview1MouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
  Layer: TCustomLayer);
begin
  if imagepreview1_mouse=false then exit;
  if Button=mbLeft then begin
    MouseDragging := False;
    imagepreview1.Cursor := crDefault;
  end;
end;

procedure TfrmEffectBase.imagepreview1MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
begin
  if imagepreview1_mouse=false then exit;
  if MouseDragging then begin
    imagepreview1.Scroll(OldMousePos.X - X, OldMousePos.Y - Y);
    OldMousePos := Point(X, Y);
  end;
end;

procedure TfrmEffectBase.FormShortCut(var Msg: TWMKey;
  var Handled: Boolean);
begin
  Handled:=false;
end;

procedure TfrmEffectBase.imagepreview1KeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
var
  NewScale:single;
begin
  case Key of
    VK_ADD:
      if imagepreview1.ScrollBars.Size=0 then begin
        NewScale:=imagepreview1.Scale+((trunc(imagepreview1.Scale)+1) / 10);
        if NewScale>200 then NewScale:=200;
        if round(NewScale*100)=100 then NewScale:=1;
        imagepreview1.Scale:=NewScale;
        isfittoscreen:=false;
        if fScaleCombo<>nil then
          fScaleCombo.Text:=format('%d %%',[round(imagepreview1.Scale*100)]);
      end;
    VK_SUBTRACT:
      if imagepreview1.ScrollBars.Size=0 then begin
        NewScale:=imagepreview1.Scale-((trunc(imagepreview1.Scale)+1) / 10);
        if NewScale<0.1 then NewScale:=0.1;
        if round(NewScale*100)=100 then NewScale:=1;
        imagepreview1.Scale:=NewScale;
        isfittoscreen:=false;
        if fScaleCombo<>nil then
          fScaleCombo.Text:=format('%d %%',[round(imagepreview1.Scale*100)]);
      end;
  end;
end;

procedure TfrmEffectBase.setScaleCombo(ScaleCombo:TComboBox);
begin
  ScaleCombo.OnChange:=ScaleCombo2Change;
  ScaleCombo.ItemIndex:=config.getvaluebyinteger('scaleindex',0);
  ScaleCombo2Change(ScaleCombo);
  fScaleCombo:=ScaleCombo;
  imagepreview1.SetFocus;
end;

procedure TfrmEffectBase.imagepreview1Resize(Sender: TObject);
begin
  if isfittoscreen then
    fittoscreen();
end;

end.
