=head1 NAME

Win32::GUI::DragDrop -- Drag-n-Drop functionality

=head1 DESCRIPTION

Win32::GUI::DragDrop enables you to drag-n-drop files on
Window and DialogBox windows.

This is the Perl-side code of the Drag-n-Drop implementation
(the other part is an XS patch).


=head1 SYNOPSIS

	##Crate the window
	# . . .

	#Make the window a drop target
	$winMain->DragAcceptFiles(1);
	my $isTarget = $winMain->DragAcceptFiles();

	#When files are dropped on the window, this event is triggered
	sub winMain_DropFiles {
		my ($handleDrop) = @_;

		my @aFilesDropped = Win32::GUI::DragDrop::GetDroppedFiles($handleDrop));

		return(1);
		}


=head1 THE XS PATCH

This code needs to be added to GUI.xs. After that, "nmake" 
and "nmake install" and you can use this module. 

If you use the module without this piece of code, people 
will be able to drop files on the window, but the 
DropFiles() event will never be triggered.

	GUI.xs, line 1839:
	----------
	    case WM_DROPFILES:
	        if(GetObjectName(NOTXSCALL hwnd, Name)) {
	            /*
	             * (@)EVENT:DropFiles(DROP_HANDLE)
	             * Sent when the window receives dropped files.
	             * (@)APPLIES_TO:Window, DialogBox
	             */
	            strcat(Name, "_DropFiles");
	            PerlResult = DoEvent_Long(NOTXSCALL Name, UINT(wParam));
	        }
	        break;
	----------

=head1 EXAMPLE PROGRAM

	#!/usr/local/bin/perl -w

	use strict;

	use Win32::GUI;
	use Win32::GUI::DragDrop;



		#Also works for Window objects
	my $winMain = new Win32::GUI::DialogBox(
	      -left   => 700,
	      -top    => 50,
	      -width  => 100,
	      -height => 100,
	      -name   => "winMain",
	      -text   => "",
	      );

		#Can drop on top of buttons
	$winMain->AddButton(
			-text    => "F",
			-name    => "btnTest",
			-left    => 0,
			-top     => 0,
			-width   => 20,
			-height  => 20,
		    );

		#Can drop on top of RichEdit (will "land" on window)
	$winMain->AddRichEdit(
			-text    => "Drop files here",
			-name    => "reTest",
			-left    => 0,
			-top     => 23,
			-width   => 90,
			-height  => 50,
		    );


	print "Initial state   : accepts drops: " . $winMain->DragAcceptFiles() . "\n";

	$winMain->DragAcceptFiles(1);
	print "After accept    : accepts drops: " . $winMain->DragAcceptFiles() . "\n";

	$winMain->DragAcceptFiles(0);
	print "After not accept: accepts drops: " . $winMain->DragAcceptFiles() . "\n";

	$winMain->DragAcceptFiles(1);
	print "After accept    : accepts drops: " . $winMain->DragAcceptFiles() . "\n";
	print "\n\n";


	$winMain->Show();
	Win32::GUI::Dialog();



	sub winMain_Terminate {
		return(-1);
		}


	sub winMain_DropFiles {
		my ($handleDrop) = @_;

		print join("\n", Win32::GUI::DragDrop::GetDroppedFiles($handleDrop)) . "\n\n";

		return(1);
		}



	#EOF

=cut





package Win32::GUI::DragDrop;





use strict;
use Win32::API;
use Win32::GUI;





=head1 ROUTINES

=head2 GetDroppedFiles($handleDrop)

Return the files associated with the $handleDrop (which you
should have received in a _DropFiles() event). Free the
memory allocated to the drag-drop operation.

Return array with files, or an empty array on errors.

=cut
sub GetDroppedFiles {
	my ($handleDrop) = @_;

	my @aFile = DragQueryFile($handleDrop);
	DragFinish($handleDrop);

	return(@aFile);
	}





=head2 DragQueryFile($handleDrop)

Return the files associated with the $handleDrop (which you
should have received in a DropFiles() event).

Return array with files, or an empty array on errors.

The GetDroppedFiles sub is preferred to this one.

=cut
my $rsDragQueryFile = new Win32::API ('shell32', 'DragQueryFileA', "NNPN", "N") || undef;
sub DragQueryFile {
	my ($handleDrop) = @_;
	my @aFile;

	return(@aFile) if($handleDrop == 0 || !defined($rsDragQueryFile));

	my $lenBuf = 1024;
	my $buffer = " " x $lenBuf;

	#Find number of files
	my $no = $rsDragQueryFile->Call($handleDrop, 0xFFFFFFFF, $buffer, $lenBuf);

	for my $i (1..$no) {
		my $lenFile = $rsDragQueryFile->Call($handleDrop, $i - 1, $buffer, $lenBuf);
		if($lenFile >= 0) {
			push(@aFile, substr($buffer, 0, $lenFile));
			}
		}

	return(@aFile);
	}





=head2 DragFinish($handleDrop)

Release memory that Windows allocated for use in
transferring filenames to the application.

Return 1 on success, else 0.

The GetDroppedFiles sub is preferred to this one.

=cut
my $rsDragFinish = new Win32::API ('shell32', 'DragFinish', "N", "") || undef;
sub DragFinish {
	my ($handleDrop) = @_;

	return(0) if(!defined($rsDragFinish));

	$rsDragFinish->Call($handleDrop) or return(0);

	return(1);
	}





=head1 Win32::GUI::Window/DialogBox methods

These are methods on Window or Dialog objects.

=cut

package Win32::GUI::Window;





=head2 DragAcceptFiles([$doAccept])

Get/set the DragAcceptFiles for the window to $doAccept
(1|0).

Return undef on errors.

=cut
my $rsDragAcceptFiles = new Win32::API ('shell32', 'DragAcceptFiles', "II", "") || undef;
my %hHwindDragAccept;
sub DragAcceptFiles { my $self = shift;
	my ($doAccept) = @_;
	return(undef) if(!defined($rsDragAcceptFiles));

	return( $hHwindDragAccept{ $self->{-handle} } || 0) if(!defined($doAccept));

	return(undef) if(!defined($rsDragAcceptFiles));
	return(undef) if($doAccept < 0 || $doAccept > 1);

	$rsDragAcceptFiles->Call($self->{-handle}, $doAccept);

	return( $hHwindDragAccept{ $self->{-handle} } = $doAccept );
	}





package Win32::GUI::DialogBox;

sub DragAcceptFiles {
	Win32::GUI::Window::DragAcceptFiles(@_);
	}





1;





#EOF
