{

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

interface

uses
  Windows, classes, CustomContextMenu, SysUtils, dialogs, clipbrd,
  graphics, FreeBitmap, FreeImage, FreeUtils, ImgList,
  registry, Udatamodule, shlobj;

const
  thisapptitle = 'nView';
  thisregname = 'nSeries\nView';

type
  TMyContextMenu = class(TOwnerDrawContextMenu)
  public
    // Basic methods
    function GetHelpText(IdCmdOffset: UINT): String; override;
    function GetVerb(IdCmdOffset: UINT): String; override;
    function AddMenuItems(Menu: HMENU; MenuIndex, IdCmdFirst, IdCmdLast: UINT): UINT; override;
    procedure ExecuteCommand(IdCmdOffset: UINT); override;
    // Owner-draw methods
    procedure MeasureMenuItem(IdCmd: UINT; var Width: UINT; var Height: UINT); override;
    procedure DrawMenuItem(Menu: HMENU; IdCmd: UINT; DC: HDC; Rect: TRect;
      State: TOwnerDrawState); override;

    destructor Destroy; override;
  private
    previewid:integer;
    subid:integer;
    subtitle:string;
    previewbmp:tbitmap;
    DataModule1:TDataModule1;

    procedure proc_wallpaper(method:integer;filename:string);
  end;

const
  GUID_ContextMenuEntry: TGUID = '{1EC8B7CE-BB7B-4108-B74C-6DB37FF99274}';
  VERB = 'nView Shellmenu';
  thumbsize = 125;
  thumbmargin = 10;

implementation
uses Ufunction, Uregistry, Ufrmoption, shellapi;

function TMyContextMenu.GetHelpText(IdCmdOffset: UINT): String;
begin
  Result := '';
end;

function TMyContextMenu.GetVerb(IdCmdOffset: UINT): String;
begin
  Result := VERB;
end;

procedure Frame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor;
  Width: Integer);

  procedure DoRect;
  var
    TopRight, BottomLeft: TPoint;
  begin
    with Canvas, Rect do
    begin
      TopRight.X := Right;
      TopRight.Y := Top;
      BottomLeft.X := Left;
      BottomLeft.Y := Bottom;
      Pen.Color := TopColor;
      PolyLine([BottomLeft, TopLeft, TopRight]);
      Pen.Color := BottomColor;
      Dec(BottomLeft.X);
      PolyLine([TopRight, BottomRight, BottomLeft]);
    end;
  end;

begin
  Canvas.Pen.Width := 1;
  Dec(Rect.Bottom); Dec(Rect.Right);
  while Width > 0 do
  begin
    Dec(Width);
    DoRect;
    InflateRect(Rect, -1, -1);
  end;
  Inc(Rect.Bottom); Inc(Rect.Right);
end;

function TMyContextMenu.AddMenuItems(Menu: HMENU; MenuIndex, IdCmdFirst, IdCmdLast: UINT): UINT;
var
  miInfo:TMenuItemInfo;
  popMenu:HMenu;

  exts,s1,filename:string;
  FBitmap:TFreeWinBitmap;
  w,h:integer;
  NewWidth,NewHeight:integer;
  r1:trect;
  thumbsize:cardinal;
  fif:FREE_IMAGE_FORMAT;
  os:integer;

  procedure addmenu(targetmenu:HMENU;id:integer;caption:string);
  begin
    FillChar(miInfo, SizeOf(miInfo), 0);
    with miInfo do begin
      cbSize := SizeOf(MenuItemInfo);
      fMask := MIIM_TYPE or MIIM_ID;
      fType := MFT_STRING;
      fState := MFS_ENABLED;
      wID := id;
      dwTypeData := PChar(caption);
      cch := Length(caption);
    end;
    InsertMenuItem(targetmenu, 0, TRUE, miInfo);
  end;

  procedure addseperate(targetmenu:HMENU;id:integer);
  begin
    FillChar(miInfo, SizeOf(miInfo), 0);
    with miInfo do begin
      cbSize := SizeOf(MenuItemInfo);
      fMask := MIIM_TYPE or MIIM_ID;
      fType := MFT_SEPARATOR;
      fState := MFS_ENABLED;
      wID := id;
    end;
    InsertMenuItem(targetmenu, 0, TRUE, miInfo);
  end;
begin
try
  result:=0;

  if FileNames.Count=0 then exit;
  filename:=FileNames.Strings[0];
  if DirectoryExists(filename) then begin
    FillChar(miInfo, SizeOf(miInfo), 0);
    miInfo.cbSize := SizeOf(miInfo);
    miInfo.fMask := MIIM_ID or MIIM_TYPE;
    miInfo.fType := MFT_OWNERDRAW;
    miInfo.fState := MFS_ENABLED;
    miInfo.dwTypeData:= pchar('preview');
    miInfo.cch:= length('preview');
    miInfo.wID := IdCmdFirst+1;
    subid:= IdCmdFirst+1;
    InsertMenuItem(Menu, MenuIndex, True, miInfo);

    result := IdCmdFirst+1;
    subtitle:='이 폴더 nView로 보기';
    exit;
  end;

  exts:=lowercase(FIU_GetFullExtList)+';';
  s1:=lowercase(ExtractFileExt(filename));
  if pos('*'+s1+';',exts)=0 then exit;

  if RegGetDWORD(HKEY_CURRENT_USER, 'software\'+thisregname+'\shellmenu\thumbsize', thumbsize)=false then
    thumbsize:=125;
  if (thumbsize<0) or (thumbsize>300) then thumbsize:=300;

  FBitmap:=TFreeWinBitmap.Create;
  try
   try
    if assigned(previewbmp) then freeandnil(previewbmp);

    if FBitmap.Load2(filename,fif) then begin
      w:=FBitmap.GetWidth;
      h:=FBitmap.GetHeight;
      subtitle:=format('(%d x %d) %d bit (%s)',[w,h,FBitmap.GetBitsPerPixel,trim(FreeImage_GetFormatFromFIF(fif))]);

      if FBitmap.IsTransparent then
        FBitmap.SetTransparentBg(nil);

      if w > h then begin
        NewWidth:=thumbsize;
        NewHeight:=Round(thumbsize * h / w);
      end else begin
        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;

      FBitmap.MakeThumbnail(NewWidth,NewHeight,FBitmap,false,thumbsize);
      FBitmap.ConvertTo24Bits;

      previewbmp:=tbitmap.Create;
      with previewbmp do begin
        PixelFormat := pf24bit;
        Width := NewWidth;
        Height := NewHeight;
        Canvas.Lock;
        try
          FBitmap.Draw(Canvas.Handle, rect(0,0,NewWidth,NewHeight));
          r1:=rect(0,0,width,height);
          Frame3D(Canvas,r1,clBtnShadow,clBtnHighlight,1);
        finally
          Canvas.Unlock;
        end;
      end;

    end else begin
      subtitle:=format('(%d x %d) %d bit (%s)',[0,0,0,'알수없음']);
    end;

   except
   end;
  finally
    FBitmap.Free;
  end;

  FillChar(miInfo, SizeOf(miInfo), 0);
  miInfo.cbSize := SizeOf(miInfo);
  miInfo.fMask := MIIM_ID or MIIM_TYPE;
  miInfo.fType := MFT_OWNERDRAW;
  miInfo.fState := MFS_ENABLED;
  miInfo.dwTypeData:= pchar('preview');
  miInfo.cch:= length('preview');
  miInfo.wID := IdCmdFirst+1;
  previewid:= IdCmdFirst+1;
  InsertMenuItem(Menu, MenuIndex, True, miInfo);

  //서브메뉴
  popMenu := CreatePopupMenu;

  addmenu(popMenu,IdCmdFirst+2,'배경화면 늘리기');
  addmenu(popMenu,IdCmdFirst+3,'배경화면 바둑판');
  addmenu(popMenu,IdCmdFirst+4,'배경화면 가운데');
  addseperate(popMenu,IdCmdFirst+5);
  addmenu(popMenu,IdCmdFirst+6,'미리보기 크기 설정');
  addmenu(popMenu,IdCmdFirst+7,'nPhotoEdit로 열기');
  addmenu(popMenu,IdCmdFirst+8,'nView로 열기');

  os:=GetOperatingSystem;
  if (os>=cOsXP) and (os<=cOsVista) then begin
    FillChar(miInfo, SizeOf(miInfo), 0);
    miInfo.cbSize := SizeOf(miInfo);
    miInfo.fMask := MIIM_SUBMENU or MIIM_ID or MIIM_TYPE;
    miInfo.fType := MFT_OWNERDRAW;
    miInfo.wID := IdCmdFirst+8;
    subid:= IdCmdFirst+8;
    miInfo.dwTypeData := nil;
    miInfo.cch := 0;
    miInfo.hSubMenu := popMenu;
    InsertMenuItem(Menu, MenuIndex, True, miInfo);
  end else begin
    InsertMenu(Menu, MenuIndex, MF_BYPOSITION or MF_POPUP, popMenu, pchar(subtitle));
  end;

  result := IdCmdFirst+8;
except
end;
end;

procedure TMyContextMenu.ExecuteCommand(IdCmdOffset: UINT);
var
  s,s1,filename:string;
  frmoption:Tfrmoption;
begin
try
  if FileNames.Count=0 then exit;
  filename:=FileNames.Strings[0];
  if DirectoryExists(filename) then begin
    case IdCmdOffset of
      1:begin
        s:=GetModuleDir+'nView.exe';
        if sysutils.FileExists(s) then begin
          s:=format('"%s" "%s"',[s,filename]);
          ExecuteFile(s,true);
        end;
      end;
    end;
    exit;
  end;

  case IdCmdOffset of
    1,8:begin
      s:=GetModuleDir+'nView.exe';
      if sysutils.FileExists(s) then begin
        s:=format('"%s" "%s"',[s,filename]);
        ExecuteFile(s,true);
      end;
    end;
    2: proc_wallpaper(3,filename);
    3: proc_wallpaper(2,filename);
    4: proc_wallpaper(1,filename);
    6:begin
      if DataModule1=nil then
        DataModule1:=TDataModule1.Create(nil);
      frmoption:=Tfrmoption.Create(nil, GetForegroundWindow);
      try
        DataModule1.ImageList1.GetIcon(0,frmoption.Icon);
        frmoption.Caption:='nView 미리보기 설정';
        frmoption.ShowModal;
      finally
        frmoption.Free;
      end;
    end;
    7:begin
      s:=GetModuleDir+'nPhotoEdit.exe';
      if sysutils.FileExists(s) then begin
        s1:=GetModuleDir+'view\edits.txt';
        FileNames.SaveToFile(s1);
        s:=format('"%s" "%s"',[s,s1]);
        ExecuteFile(s,true);
      end;
    end;
  end;
except
end;
end;

procedure TMyContextMenu.MeasureMenuItem(IdCmd: UINT; var Width: UINT; var Height: UINT);
begin
try
  if IdCmd=previewid then begin
    if assigned(previewbmp) then begin
      Width:=previewbmp.Width+thumbmargin;
      Height:=previewbmp.Height+thumbmargin;
    end else begin
      Width:=thumbmargin;
      Height:=thumbmargin;
    end;
  end else if IdCmd=subid then begin
    width:=GetStandardTextWidth(subtitle)+16;
    height:=GetStandardMenuItemHeight;
  end;
except
end;
end;

procedure TMyContextMenu.DrawMenuItem(Menu: HMENU; IdCmd: UINT; DC: HDC; Rect: TRect;
  State: TOwnerDrawState);
var
  x,y:integer;
  Bmp:Tbitmap;
  font,oldfont:HFONT;
  filename:string;
  textsize:TSize;
begin
try
  if FileNames.Count=0 then exit;

  if odSelected in State then
  begin
    SetBkColor(DC, GetSysColor(COLOR_HIGHLIGHT));
    SetTextColor(DC, GetSysColor(COLOR_HIGHLIGHTTEXT));
    FillRect(DC, Rect, HBRUSH(COLOR_HIGHLIGHT+1));
  end
  else
  begin
    SetBkColor(DC, GetSysColor(COLOR_MENU));
    SetTextColor(DC, GetSysColor(COLOR_MENUTEXT));
    FillRect(DC, Rect, HBRUSH(COLOR_MENU+1));
  end;

  filename:=FileNames.Strings[0];
  if DirectoryExists(filename) then begin
    if IdCmd=subid then begin
      if DataModule1=nil then
        DataModule1:=TDataModule1.Create(nil);
      Bmp:=tbitmap.Create;
      try
        DataModule1.ImageList1.GetBitmap(0,bmp);
        bmp.PixelFormat:=pf8bit;
        x:=(GetSystemMetrics(SM_CXMENUCHECK)-Bmp.Width) div 2;
        if x<0 then x:=0;
        x:=Rect.Left+x;
        y:=Rect.Top+((rect.Bottom-rect.Top)-Bmp.Height) div 2;
        DrawTransparentBitmap(DC, Bmp.Handle, x, y, clwhite);

        x:=Rect.Left+GetSystemMetrics(SM_CXMENUCHECK)+GetSystemMetrics(SM_CXFRAME);
        GetTextExtentPoint32(DC, PChar(subtitle), Length(subtitle), textsize);
        y:=Rect.Top+((rect.Bottom-rect.Top)-textsize.cy) div 2;
        TextOut(DC, x, y, PChar(subtitle), Length(subtitle));
      finally
        bmp.Free;
      end;
    end;
    exit;
  end;

  if (IdCmd=previewid) and assigned(previewbmp) then begin
    x:=((rect.Right-rect.Left) div 2)-(previewbmp.Width div 2);
    y:=Rect.Top+(thumbmargin div 2);
    BitBlt(DC,
         x,y,previewbmp.Width,previewbmp.Height,
         previewbmp.Canvas.Handle,0,0, SRCCOPY);

  end else if (IdCmd=subid) then begin
    if DataModule1=nil then
      DataModule1:=TDataModule1.Create(nil);

    Bmp:=tbitmap.Create;
    try
      DataModule1.ImageList1.GetBitmap(0,bmp);
      bmp.PixelFormat:=pf8bit;
      x:=(GetSystemMetrics(SM_CXMENUCHECK)-Bmp.Width) div 2;
      if x<0 then x:=0;
      x:=Rect.Left+x;
      y:=Rect.Top+((rect.Bottom-rect.Top)-Bmp.Height) div 2;
      DrawTransparentBitmap(DC, Bmp.Handle, x, y, clwhite);

      font:=CreateFont(Rect.Bottom-Rect.Top-5,
           0,0,0,0,0,0,0,HANGEUL_CHARSET,0,0,0,0,'굴림');
  		oldfont:=SelectObject(DC,font);

      x:=Rect.Left+GetSystemMetrics(SM_CXMENUCHECK)+GetSystemMetrics(SM_CXFRAME);
      GetTextExtentPoint32(DC, PChar(subtitle), Length(subtitle), textsize);
      y:=Rect.Top+((rect.Bottom-rect.Top)-textsize.cy) div 2;

      TextOut(DC, x, y, PChar(subtitle), Length(subtitle));
      SelectObject(DC,oldfont);
   		DeleteObject(font);
    finally
      bmp.Free;
    end;
  end;
except
end;
end;


procedure TMyContextMenu.proc_wallpaper(method:integer;filename:string);
var
  reg: TRegIniFile;
  tfilename:string;
  FBitmap:TFreeWinBitmap;
begin
try
  FBitmap:=TFreeWinBitmap.Create;
  try
    try
      FBitmap.Load(filename);
//      tfilename:=GetWindowsDir+'nView 배경화면.bmp';
      tfilename:=GetShellPath(CSIDL_APPDATA)+thisregname;
      sysutils.ForceDirectories(tfilename);
      tfilename:=tfilename+'\nView 배경화면.bmp';
      FBitmap.Save(tfilename);
    except
      on E: Exception do begin
        MessageDlg(E.Message,mtError, [mbOk], 0);
        exit;
      end;
    end;
  finally
    FBitmap.Free;
  end;

  reg := TRegIniFile.Create('Control Panel\Desktop');
  try
    with reg do
    begin
      WriteString('', 'Wallpaper', tfilename);
      case method of
        1:begin
         //center
         WriteString('', 'TileWallpaper', '0');
         WriteString('','WallpaperStyle','0');
        end;
        2:begin
         //tile
         WriteString('', 'TileWallpaper', '1');
         WriteString('','WallpaperStyle','0');
        end;
        3:begin
        //resize
         WriteString('', 'TileWallpaper', '0');
         WriteString('','WallpaperStyle','2');
        end;
      end;
    end;
  finally
    reg.Free;
  end;
  SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, nil, SPIF_SENDWININICHANGE);
  if IsActiveDeskTopOn then
     ChangeWallpaper(tfilename);
  MessageDlg('윈도우 배경화면을 변경했습니다.', mtInformation, [mbOk], 0);
except
end;
end;

destructor TMyContextMenu.Destroy;
begin
try
  if assigned(previewbmp) then freeandnil(previewbmp);
  if assigned(DataModule1) then freeandnil(DataModule1);
except
end;
  inherited;
end;

initialization
  Initialize(TMyContextMenu, GUID_ContextMenuEntry, 'nView Shellmenu');

finalization

end.

