unit DropPnl;

{ (C) 1995, ingenieursbureau Office Automation
  All Rights Reserved

  Hereby the right to distribute this work electronically is granted,
  provided such is done for at most a nominal fee. Also the right is
  granted to store this work on a computer system.
  Finally the right is granted to incorporate this work into other
  work provided no fee is asked for this work.
  In all cases of distribution this work must be distributed in full,
  which specifically includes this notice.
  Liability is limited to the amount payed for this work. Legal
  jurisdiction is with the court of Leeuwarden, the Netherlands.

  Roelof Osinga, 29 december 1995
}

interface

uses
  WinTypes, WinProcs, Messages, Classes, Controls, Forms, Graphics,
  StdCtrls, ExtCtrls, Buttons, ShellApi, SysUtils;

type
  TDropActions = (daSimple, daRecursive, daEventOnly);

  TDropEvent = procedure(Sender : TObject; FileList : TStringList; X, Y: Integer) of object;

  TDropPanel = class(TPanel)
  protected
    FDroppedList : TStringList;
    FDroppedPoint : TPoint;
    FDropAction : TDropActions;
    FAtRunTime : boolean;
    FOnDrop : TDropEvent;
    function HandleDroppedGlyphs(aGlyph : TBitmap; const aStr : string) : integer;
    procedure HandleDroppedBitBtnGlyphs(aComp : TBitBtn; const aStr : string);
    procedure HandleDroppedSpeedButtonGlyphs(aComp : TSpeedButton; const aStr : string);
    procedure HandleDroppedFiles;
    function HandleDroppedFilesRec(aComp : TWinControl; dropAt : TPoint) : boolean;
    procedure CreateParams(var Params : TCreateParams); override;
    procedure WMDropFiles(var Message : TMessage); message WM_DROPFILES;
    destructor Destroy; override;
  public
    constructor Create(anOwner : TComponent); override;
  published
    property DropAction : TDropActions read FDropAction write FDropAction default daRecursive;
    property AtRunTime : boolean read FAtRunTime write FAtRunTime default true;
    property OnDrop : TDropEvent read FOnDrop write FOnDrop;
  end;

procedure Register;

implementation

constructor TDropPanel.Create(anOwner : TComponent);
begin
  inherited Create(anOwner);
  FDroppedList := TStringList.Create;
  FDroppedPoint := Point(0,0);
  FDropAction := daRecursive;
  FAtRunTime := true;
end;

destructor TDropPanel.Destroy;
begin
  FDroppedList.Free;
  inherited Destroy;
end;

procedure TDropPanel.CreateParams(var Params : TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
  begin
    ExStyle := ExStyle or WS_EX_ACCEPTFILES;
  end;
end;

function TDropPanel.HandleDroppedGlyphs(aGlyph : TBitmap; const aStr : string) : integer;
var Glyphs : integer;
begin
  Result := 1;
  try
    aGlyph.LoadFromFile(aStr);
    if (aGlyph.Width mod aGlyph.Height) = 0
    then begin
      Glyphs := aGlyph.Width div aGlyph.Height;
      if Glyphs > 4
      then Glyphs := 1;
      Result := Glyphs;
    end;
  except
    ;
  end;
end;

procedure TDropPanel.HandleDroppedBitBtnGlyphs(aComp : TBitBtn; const aStr : string);
begin
  aComp.NumGlyphs := HandleDroppedGlyphs(aComp.Glyph, aStr); {FDroppedList[0]);}
end;

procedure TDropPanel.HandleDroppedSpeedButtonGlyphs(aComp : TSpeedButton; const aStr : string);
begin
  aComp.NumGlyphs := HandleDroppedGlyphs(aComp.Glyph, aStr); {FDroppedList[0]);}
end;

procedure TDropPanel.HandleDroppedFiles;
var
  i, j, nL, nC : integer;
  comp : TComponent;
begin
  nL := FDroppedList.Count - 1;
  if nL > -1
  then begin
    nC := ControlCount - 1;
    for i := 0 to nC do
    begin
      comp := Controls[i];
      if PtInRect(TControl(comp).BoundsRect, FDroppedPoint)
      then begin
         if comp is TImage
         then (comp as TImage).Picture.LoadFromFile(FDroppedList[0]);
         if comp is TMemo
         then (comp as TMemo).Lines.LoadFromFile(FDroppedList[0]);
         if (comp is TBitBtn)
         then HandleDroppedBitBtnGlyphs(TBitBtn(comp), FDroppedList[0]);
         if (comp is TSpeedButton)
         then HandleDroppedSpeedButtonGlyphs(TSpeedButton(comp), FDroppedList[0]);
       end;
    end;
  end;
end;

function TDropPanel.HandleDroppedFilesRec(aComp : TWinControl; dropAt : TPoint) : boolean;
var
  i, nL, nC : integer;
  done : boolean;
  aControl : TComponent;
begin
  done := false;
  nL := FDroppedList.Count - 1;
  if nL > -1
  then begin
    nC := aComp.ControlCount - 1;
    i := -1;
    while not done and (i < nC) do
    begin
      inc(i);
      aControl := aComp.Controls[i];
      if PtInRect(TControl(aControl).BoundsRect, dropAt)
      then begin
         if not done and (aControl is TImage)
         then begin
           try
             (aControl as TImage).Picture.LoadFromFile(FDroppedList[0]);
           except ;
           end;
           done := true;
         end;
         if not done and (aControl is TMemo)
         then begin
           (aControl as TMemo).Lines.LoadFromFile(FDroppedList[0]);
           done := true;
         end;
         if not done and (aControl is TBitBtn)
         then begin
           HandleDroppedBitBtnGlyphs(TBitBtn(aControl), FDroppedList[0]);
           done := true;
         end;
         if not done and (aControl is TSpeedButton)
         then begin
           HandleDroppedSpeedButtonGlyphs(TSpeedButton(aControl), FDroppedList[0]);
           done := true;
         end;
         if not done and (aControl is TWinControl) and
           not ((aControl is TMemo) or (aControl is TBitBtn))
         then begin
           done := HandleDroppedFilesRec(TWinControl(aControl),
                     TWinControl(aControl).ScreenToClient(aComp.ClientToScreen(dropAt)) );
         end;
       end;
    end;
  end;
  if not done and (aComp = Self)
  then MessageBeep(0);
  Result := done;
end;

procedure TDropPanel.WMDropFiles(var Message : TMessage);
var
  hDrop : THandle;
  nFiles, i, size : word;
  Pstr : PChar;
begin
  hDrop := Message.WParam;
  Pstr := StrAlloc(256);
  Message.Result := 0; {accept}
  try
    DragQueryPoint(hDrop, FDroppedPoint);
    nFiles := DragQueryFile(hDrop, $FFFF, Pstr, size);
    dec(nFiles);
    FDroppedList.Clear;
    for i := 0 to nFiles do
    begin
      {size := DragQueryFile(hDrop, i, nil, size);}
      size := 255;
      size := DragQueryFile(hDrop, i, Pstr, size+1);
      FDroppedList.Add(StrPas(Pstr));
    end;
  finally
    DragFinish(hDrop);
    StrDispose(Pstr);
  end;
  if Assigned(FOnDrop)
  then FOnDrop(Self, FDroppedList, FDroppedPoint.X, FDroppedPoint.Y);
  if FAtRunTime or (csDesigning in ComponentState)
  then
    case FDropAction of
      daSimple : HandleDroppedFiles;
      daRecursive : HandleDroppedFilesRec(Self, FDroppedPoint);
    end;
end;

procedure Register;
begin
  RegisterComponents('IBOA', [TDropPanel]);
end;

end.
