{

   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_Filter;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, UfrmEffectBase, ComCtrls, StdCtrls, Spin, ExtCtrls, gr32;

type
  TfrmEffect_Filter = class(TfrmEffectBase)
    Panel1: TPanel;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    ListBox1: TListBox;
    TabSheet2: TTabSheet;
    efftree: TTreeView;
    effbar0: TTrackBar;
    Edit18: TSpinEdit;
    effbar1: TTrackBar;
    Edit17: TSpinEdit;
    effbar2: TTrackBar;
    Edit16: TSpinEdit;
    Panel2: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ListBox1ListBoxClick(Sender: TObject);
    procedure efftreeClick(Sender: TObject);
    procedure effbar0Change(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Edit17Change(Sender: TObject);
  private
    { Private declarations }
    //convolution
    EffMatrix : array [0..6,0..6] of integer;
    divisor:integer;
    mx:integer;
    fbasicfilter,fadvancefilter:boolean;
    tempbitmap:tbitmap32;
    noapplyimgview:boolean;
    blockapply:boolean;

    procedure UpdateConvolution;
    function getmatrixsize():integer;
    procedure FillTreeView;
    procedure ExpandAll;
    procedure bar(min0,max0,pos0,min1,max1,pos1,min2,max2,pos2:integer);
    procedure ok_select; override;
    procedure imageprocess(var src:tbitmap);
    procedure set_effectapply;
  public
    { Public declarations }
  end;

var
  frmEffect_Filter: TfrmEffect_Filter;

implementation
uses im_Convolution, im_Effects, im_Basic, Uconfig, Ufunction, UfrmMain;

{$R *.dfm}

procedure TfrmEffect_Filter.FormCreate(Sender: TObject);
var
  i:integer;
begin
  inherited;
  PanelPreView.Width:=245;
  PanelPreView.Align:=alLeft;

  self.Panel1.Align:=alclient;
  PageControl1.Align:=alclient;

  for i := Low(CONVOLUTION_FILTERNAMES) to High(CONVOLUTION_FILTERNAMES) do
    listbox1.Items.Add(CONVOLUTION_FILTERNAMES[i]);
  listbox1.ItemIndex := 0;

  FillTreeView;
  self.Width:=720;

  fbasicfilter:=false;
  fadvancefilter:=false;
  tempbitmap:=tbitmap32.Create;
end;

procedure TfrmEffect_Filter.FormDestroy(Sender: TObject);
begin
  inherited;
  config.setvaluebyinteger('filter_selectpage',PageControl1.ActivePageIndex);

  if self.PageControl1.ActivePageIndex=0 then begin
    if fbasicfilter then begin
      config.setvaluebyinteger('filter_basicfilter',1);
      config.setvaluebyinteger('filter_basicfilter_idx',ListBox1.ItemIndex);
    end else
      config.setvaluebyinteger('filter_basicfilter',0);
  end else begin
    if Fadvancefilter and (efftree.Selected<>nil) then begin
      config.setvaluebyinteger('filter_advancefilter',1);
      config.setvaluebyinteger('filter_advancefilter_idx',efftree.Selected.ImageIndex);
    end else
      config.setvaluebyinteger('filter_advancefilter',0);
  end;

  tempbitmap.Free;
end;

procedure TfrmEffect_Filter.FormShow(Sender: TObject);
var
  i,idx:integer;
begin
  make_thumbimage;
  imagepreview1.Bitmap.Assign(thumb_bitmap32);

  applyselect.Visible:=not frmmain.is_layerselected;

  PageControl1.ActivePageIndex:=config.getvaluebyinteger('filter_selectpage');

  if PageControl1.ActivePageIndex=0 then begin
    if config.getvaluebyinteger('filter_basicfilter',0)=1 then begin
      self.ListBox1.ItemIndex:=config.getvaluebyinteger('filter_basicfilter_idx',0);
      ListBox1ListBoxClick(nil);
    end;
  end else begin
    if config.getvaluebyinteger('filter_advancefilter',0)=1 then begin
      idx:=config.getvaluebyinteger('filter_advancefilter_idx',0);
      for i:=0 to efftree.Items.Count-1 do
        if efftree.Items[i].ImageIndex=idx then begin
          efftree.Items[i].Selected:=true;
          efftreeClick(nil);
          PageControl1.ActivePageIndex:=1;
          break;
        end;
    end;
  end;
end;

procedure TfrmEffect_Filter.UpdateConvolution;
var ray:array [0..49] of integer;
    EffMatrix2 : array [0..6,0..6] of integer;
    i,j,k:integer;
    mx:integer;
begin
  mx:=getmatrixsize();
  k:=0;
  for i:=0 to 49 do ray[i]:=0;

 case mx of
 3: begin
    for i:=2 to 6 do for j:=2 to 6 do
    effmatrix2[i-2,j-2]:=effmatrix[i,j];
      for i:=0 to 2 do for j:=0 to 2 do
      begin
       ray[k]:=effmatrix2[j,i];
       inc(k);
      end;
     ray[49]:=divisor;
    end;
 5: begin
    for i:=1 to 6 do for j:=1 to 6 do
    effmatrix2[i-1,j-1]:=effmatrix[i,j];
      for i:=0 to 4 do for j:=0 to 4 do
      begin
       ray[k]:=effmatrix2[j,i];
       inc(k);
      end;
     ray[49]:=divisor;
    end;
  7: begin
      for i:=0 to 6 do for j:=0 to 6 do
      begin
       ray[k]:=effmatrix[j,i];
       inc(k);
      end;
      ray[49]:=divisor;
     end;
   end;

  applyconvolution(tempbitmap,ray,mx);
end;

function TfrmEffect_Filter.getmatrixsize():integer;
var i:integer;
begin
result:=7;
 for i:=0 to 6 do if effmatrix[i,0]<>0 then exit;
 for i:=0 to 6 do if effmatrix[i,6]<>0 then exit;
 for i:=0 to 6 do if effmatrix[0,i]<>0 then exit;
 for i:=0 to 6 do if effmatrix[6,i]<>0 then exit;
result:=5;
 for i:=1 to 5 do if effmatrix[i,1]<>0 then exit;
 for i:=1 to 5 do if effmatrix[i,5]<>0 then exit;
 for i:=1 to 5 do if effmatrix[1,i]<>0 then exit;
 for i:=1 to 5 do if effmatrix[5,i]<>0 then exit;
result:=3;
end;

procedure TfrmEffect_Filter.ListBox1ListBoxClick(Sender: TObject);
var
  i,j:integer;
  hm:tconvolutionkernel;
  k:integer;
begin
try
  Screen.Cursor := crHourglass;
  tempbitmap.Assign(thumb_bitmap32);
  hm:=(KERNEL_ARRAY[listbox1.ItemIndex]);
  k:=0;
  for i:=0 to 6 do
   for j:=0 to 6 do begin
     effmatrix[j,i]:=hm[k];
     inc(k);
  end;
  divisor:=hm[49];
  UpdateConvolution;
  fbasicfilter:=true;

  if noapplyimgview=false then begin
    imagepreview1.bitmap.Assign(tempbitmap);
    imagepreview1.bitmap.changed;
  end;
finally
  Screen.Cursor := crDefault;
end;
end;

procedure TfrmEffect_Filter.FillTreeView;
const
   filters=25;
   TextArray : array[1..filters] of string =
   ('Add Mono Noise', 'Add Color Noise', 'Gaussian Blur', 'SplitBlur',
    'Posterize', 'Solarize', 'Mosaic', 'Twist',
    'FishEye', 'WaveH','Emboss',
    'Dither BW','Scroll','Gradient','Average',
    'Median','Wave2','GreyScaleErosion','GreyScaleDilation',
    'GreyScaleOpening','GreyScaleClosing','ItAndMiss','Kuwahara',
    'Outline','Tile'
   );

var
   Index : Integer;
   Root  : TTreeNode;
   Node  : TTreeNode;
begin
   efftree.Items.BeginUpdate;
   Root := efftree.Items.Add(nil, 'Filter');
   for Index := 1 to filters do
   begin
      Node := efftree.Items.AddChild(Root, TextArray[Index]);
      efftree.Items.Item[index].ImageIndex:=index;
   end;
   efftree.Items.EndUpdate;
   ExpandAll;
end;

procedure TfrmEffect_Filter.ExpandAll;
var
  Node: TTreeNode;
begin
  Node := efftree.Items.GetFirstNode;
  while Node <> nil do
  begin
    Node.Expand(True);
    Node := Node.GetNextSibling;
  end;
end;


procedure TfrmEffect_Filter.efftreeClick(Sender: TObject);
var index:integer;
begin
Screen.Cursor := crHourGlass;
if effTree.Selected =nil then exit;
index:=effTree.Selected.ImageIndex;
if index<0 then exit;
case index of
 1: bar(0,1000,128,0,0,0,0,0,0);//filter mononoise
 2: bar(0,1000,128,0,0,0,0,0,0);//filter colornoise

 3: bar(0,20,0,0,0,0,0,0,0);//filter gaussianblur
 4: bar(0,30,0,0,0,0,0,0,0);//filter splitblur

 5: bar(1,255,128,0,0,0,0,0,0);//filter Posterize
 6: bar(0,255,128,0,0,0,0,0,0);//filter Solarize

 7: bar(0,255,10,0,0,0,0,0,0);//filter Mosaic
 8: bar(1,255,50,0,0,0,0,0,0);//Twist
 9: bar(1,50,10,0,0,0,0,0,0);//FishEye

 10: bar(1,50,25,1,50,1,0,2,0);//waveH
// 11: bar(0,4096,512,0,4096,512,0,0,0);
 11: bar(0,0,0,0,0,0,0,0,0);
 12: bar(0,0,0,0,0,0,0,0,0);
 13: bar(0,org_bitmap32.Width-1,0,0,org_bitmap32.height-1,0,0,0,0);
 14: bar(0,255,0,0,255,255,0,3,0);
 15: bar(0,0,0,0,0,0,0,0,0);
 16: bar(0,0,0,0,0,0,0,0,0);
 17: bar(1,50,25,1,50,1,0,2,0);
 18: bar(0,0,0,0,0,0,0,0,0);
 19: bar(0,0,0,0,0,0,0,0,0);
 20: bar(0,0,0,0,0,0,0,0,0);
 21: bar(0,0,0,0,0,0,0,0,0);
 22: bar(0,0,0,0,0,0,0,0,0);
 23: bar(0,0,0,0,0,0,0,0,0);
 24: bar(0,0,0,0,0,0,0,0,0);
 25: bar(1,16,2,0,0,0,0,0,0);
end;
effbar0change(self);
fadvancefilter:=true;
Screen.Cursor := crDefault;
end;

procedure TfrmEffect_Filter.effbar0Change(Sender: TObject);
var index:integer;
    rdbar1,rdbar2,rdbar3:integer;
begin
if blockapply then exit;
rdbar1:=effbar0.Position;
rdbar2:=effbar1.Position;
rdbar3:=effbar2.Position;

edit18.text:=inttostr(rdbar1);
edit17.text:=inttostr(rdbar2);
edit16.text:=inttostr(rdbar3);

tempbitmap.Assign(thumb_bitmap32);

if EffTree.selected=nil then exit;
index:=EffTree.selected.ImageIndex;
if index<0 then exit;
case index of
 1: Effect_AddMonoNoise(tempbitmap,rdbar1);
 2: Effect_AddColorNoise(tempbitmap,rdbar1);
 3: Effect_GaussianBlur(tempbitmap,rdbar1);
 4: Effect_SplitBlur(tempbitmap,rdbar1);
 5: Effect_Posterize(tempbitmap,rdbar1);
 6: Effect_Solarize(tempbitmap,rdbar1);
 7: Effect_Mosaic(tempbitmap,round(rdbar1*thumbratio));
 8: Effect_Twist(tempbitmap,round(rdbar1*thumbratio));
 9: Effect_Fisheye(tempbitmap,rdbar1);
 10: Effect_WaveH(tempbitmap,round(rdbar1*thumbratio),rdbar2,rdbar3);
// 11: Effect_Addborder(tempbitmap,rdbar1,rdbar2);
 11: Effect_Emboss(tempbitmap);
 12: Bitmap32FloydSteinbergDitherBW(tempbitmap);
 13: Effect_ShiftXY(tempbitmap,round(rdbar1*thumbratio),round(rdbar2*thumbratio));
 14: Effect_Gradient(tempbitmap,rdbar1,rdbar2,rdbar3);
 15: Effect_Average(tempbitmap);
 16: Effect_Median(tempbitmap);
 17: Effect_Wave2(tempbitmap,round(rdbar1*thumbratio),rdbar2,rdbar3);
 18: Effect_GreyScaleErosion(tempbitmap);
 19: Effect_GreyScaleDilation(tempbitmap);
 20: Effect_GreyScaleOpening(tempbitmap);
 21: Effect_GreyScaleClosing(tempbitmap);
 22: Effect_GreyScaleItAndMiss(tempbitmap);
 23: Kuwahara5x5(tempbitmap);
 24: Effect_Outline(tempbitmap);
 25: Effect_Tile(tempbitmap,rdbar1);
 end;

  if noapplyimgview=false then begin
    imagepreview1.Bitmap.Assign(tempbitmap);
    imagepreview1.Bitmap.Changed;
  end;
end;

procedure TfrmEffect_Filter.bar(min0,max0,pos0,min1,max1,pos1,min2,max2,pos2:integer);
begin
blockapply:=true;
try
 if min0>effbar0.Max then effbar0.Max:=max0;
 effbar0.Min:=min0;
 effbar0.Max:=max0;
 effbar0.Position:=pos0;
 effbar0.Frequency:=(max0-min0)*5 div 180;
 if effbar0.Frequency<=0 then effbar0.Frequency:=1;
 Edit18.MinValue:=min0;
 Edit18.MaxValue:=max0;

 if min1>effbar1.Max then effbar1.Max:=max1;
 effbar1.Min:=min1;
 effbar1.Max:=max1;
 effbar1.Position:=pos1;
 effbar1.Frequency:=(max1-min1)*5 div 180;
 if effbar1.Frequency<=0 then effbar1.Frequency:=1;
 Edit17.MinValue:=min1;
 Edit17.MaxValue:=max1;
finally
  blockapply:=false;
end;

 if min2>effbar2.Max then effbar2.Max:=max2;
 effbar2.Min:=min2;
 effbar2.Max:=max2;
 effbar2.Position:=pos2;
 effbar2.Frequency:=(max2-min2)*5 div 180;
 if effbar2.Frequency<=0 then effbar2.Frequency:=1;
 Edit16.MinValue:=min2;
 Edit16.MaxValue:=max2;

 effbar0.visible:=true;
 effbar1.Visible:=true;
 effbar2.Visible:=true;
 edit18.visible:=true;
 edit17.visible:=true;
 edit16.visible:=true;

 if (max0=0) and (min0=0) and (pos0=0) then begin effbar0.Visible:=false; edit18.visible:=false; end;
 if (max1=0) and (min1=0) and (pos1=0) then begin effbar1.Visible:=false; edit17.visible:=false; end;
 if (max2=0) and (min2=0) and (pos2=0) then begin effbar2.Visible:=false; edit16.visible:=false; end;

end;

procedure TfrmEffect_Filter.set_effectapply;
begin
  thumbratio:=1;
  thumb_bitmap32.Assign(org_bitmap32);

  if self.PageControl1.ActivePageIndex=0 then begin
    if fbasicfilter then
      ListBox1ListBoxClick(nil);
  end else begin
    if fadvancefilter then begin
      if (effbar0.Visible) or (effbar1.Visible) or (effbar2.Visible) then
        effbar0Change(nil)
      else
        efftreeClick(nil);
    end;
  end;
end;

procedure TfrmEffect_Filter.ok_select;
begin
  if applyselect.ItemIndex=0 then begin
    Screen.Cursor:=crHourglass;
    try
      set_effectapply;
    finally
      Screen.Cursor:=crDefault;
    end;
    exit;
  end;

  frmmain.apply_listimages(applyselect.ItemIndex=1,imageprocess,etfilter,self.Caption);
  self.ModalResult:=mrcancel;
end;

procedure TfrmEffect_Filter.imageprocess(var src:tbitmap);
begin
  org_bitmap32.Assign(src);
  noapplyimgview:=true;
  try
    set_effectapply;
  finally
    noapplyimgview:=false;
  end;
  tempbitmap.AssignTo24(src);
end;

procedure TfrmEffect_Filter.Edit17Change(Sender: TObject);
begin
  if isvalidinteger(edit18.Text) then effbar0.Position:=round(edit18.Value);
  if isvalidinteger(edit17.Text) then effbar1.Position:=round(edit17.Value);
  if isvalidinteger(edit16.Text) then effbar2.Position:=round(edit16.Value);
end;

end.
