#!perl -w
# Listview with drag and drop capaility
# Authors: Chris Wearn, Jez White, Robert May
# July 2005
use strict;
use warnings;
use Win32::GUI 1.03_03, qw(TPM_LEFTALIGN TPM_TOPALIGN TPM_RIGHTBUTTON
ILC_COLOR ILC_COLOR24 ILC_MASK
WM_CONTEXTMENU CW_USEDEFAULT
LVS_ICON LVS_REPORT LVS_SMALLICON LVS_LIST
LVIR_SELECTBOUNDS LVSIL_SMALL);
use Win32::GUI::BitmapInline ();
our $VERSION = "0.01";
my $DEBUG=0; # set to a false value to turn off debugging output
my $NUM_ITEMS = 20; # set to the number of items you want in the listview
my $dragInfo = {
dragging => 0, # flag to indicate whether we are dragging or not
cursor_start_x => undef, # cursor x position in view coordinates at start of move
cursor_start_y => undef, # cursor y position in view coordinates at start of move
};
######################################################################
# Cursor for use when dragging
my $curDrag = newCursor Win32::GUI::BitmapInline( q(
AAACAAEAICAAABAACAAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAAAA
AAAAAAAAAAAA////AAAACqoAABVVAAAIAgAAEAEAAAgCAAAQgQAACMIAABWVAAAJqgAAAwAAAEMA
AABmAAAAfgAAAH4AAAB/wAAAf4AAAH8AAAB+AAAAfBAAAHgoAABwbAAAYIIAAEBsAAAAKAAAABAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///gAP//4AD//+f8///n/P//53z//+Yc///mHP//
4CD//2QA//84f///GH///wD///8A////AA///wAf//8AP///AH///wD///8B7///A8f//weD//8P
Af//H4P//z/H////7/////////////////////////////////////8=
) );
######################################################################
# Create Main window
my $mw = Win32::GUI::Window->new(
-title => "ListView Drag and Drop Sample",
-left => CW_USEDEFAULT, # let the window manager select the position
-size => [500,500],
-onResize => \&resize
);
######################################################################
# Create ImageLists
my($ilLarge, $ilSmall) = CreateImageLists();
######################################################################
# Create ListView
my $lv = $mw->AddListView(
-imagelist => $ilLarge,
-width => $mw->ScaleWidth(),
-height => $mw->ScaleHeight(),
-editlabel => 1,
-onBeginDrag => \&beginDrag,
-onBeginLabelEdit => sub { return 1;},
-onEndLabelEdit => sub { $_[0]->SetItemText($_[1],$_[2]) if defined $_[2] ; return 1; },
-onMouseMove => \&drag,
-onMouseUp => \&endDrag,
-onMouseDown => \&preDrag,
);
# Set the small icon imagelist (-imagelist option to AddListView
# sets both imagelists to be the same)
$lv->SetImageList($ilSmall, LVSIL_SMALL);
# Set large icon view (report view is the default)
$lv->View(LVS_ICON);
######################################################################
# Add columns for the 'report' view
$lv->InsertColumn( -text => "Column1", -width => 100);
$lv->InsertColumn( -text => "Column2", -width => 100);
$lv->InsertColumn( -text => "Column3", -width => 100);
######################################################################
# Add items to the listview
# Currently undocumented that -text item can take an array ref
# containing text for multiple columns
for my $i (1..$NUM_ITEMS) {
$lv->InsertItem( -image => 0, -text => ["Item ".$i, "Phone", 1024*$i],);
}
######################################################################
# Hook WM_CONTEXTMENU as the procedure to show our context menu
# WM_CONTEXTMENU is better that onMouseRightUp, as it is also
# generated for the keyboard menu key
$lv->Hook(WM_CONTEXTMENU, \&lvPopup);
######################################################################
# Some menu definitions, used for the context menus
my $Menus = Win32::GUI::Menu->new(
"General Menu" => "General",
"> &Select All" => { -name => "SelectAll", -onClick => sub { select_all ($lv); }, },
"> &Deselect All" => { -name => "DeselectAll", -onClick => sub { deselect_all($lv); }, },
"> &Arrange" => { -name => "Arrange", -onClick => sub { arrange ($lv); }, },
"> -" => 0,
"> View" => "View",
">> Lar&ge Icons" => { -name => "Large", -onClick => sub { change_view ($lv, LVS_ICON); }, },
">> S&mall Icons" => { -name => "Small", -onClick => sub { change_view ($lv, LVS_SMALLICON); }, },
">> &List" => { -name => "List", -onClick => sub { change_view ($lv, LVS_LIST); }, },
">> &Details" => { -name => "Details", -onClick => sub { change_view ($lv, LVS_REPORT); }, },
"Item Menu" => "Item",
"> &Edit Label" => { -name => "EditLabel", -onClick => sub { edit_label ($lv); }, },
"> &Change Icon" => { -name => "ChangeIcon", -onClick => sub { change_icon ($lv); }, },
"> &Invert Selection" => { -name => "Invert", -onClick => sub { invert_sel ($lv); }, },
);
######################################################################
# Show the window and enter the dialog phase
$mw->Show();
Win32::GUI::Dialog();
exit(0);
######################################################################
# Event Handlers
######################################################################
######################################################################
# Called on left mouse down, before starting a drag
# use this to record the drag start position, as by the time we see a
# BeginDrag event, the cursor has moved (4 pixels I think).
sub preDrag
{
my($control, $x, $y) = @_;
print "Thinking about dragging? ($x, $y) - client coordinates\n" if $DEBUG;
#convert cursor position into listview view coordinates
my ($vox, $voy) = $control->GetOrigin();
($vox, $voy) = (0,0) if not defined $vox; # GetOrigin returns undef for list and report views
my ($cvx, $cvy) = ($x + $vox, $y + $voy);
print "\tCursor at ($cvx, $cvy) - listview view coordinates\n" if $DEBUG;
# store the potential start cursor position
$dragInfo->{cursor_start_x} = $cvx;
$dragInfo->{cursor_start_y} = $cvy;
return 1;
}
######################################################################
# Called when a selected set of items is starting to be dragged
sub beginDrag
{
my ($control, $item) = @_;
my $dix; # left corner of drag image
my $diy; # top corner of drag image
my $dimagelist; # the drag image we create
print "BeginDrag Event received for item $item (zero-based index)\n" if $DEBUG;
# we're going to need to do a number of client to listview view coordinate
# conversions, so get the listview origin here, once
my ($vox, $voy) = $control->GetOrigin();
($vox, $voy) = (0,0) if not defined $vox; # GetOrigin returns undef for list and report views
# create the drag image
for my $i ($control->SelectedItems()) {
# Get the position of the image that will be created by CreateDragImage
# NOTE: This is the top left of the rect around the icon and label, NOT
# the top left of the item rect as returned by GetItemPosition
# LVIR_SELECTBOUNDS returns the union of LVIR_ICON and LVIR_LABEL.
# GetItemRect returns it's value in client coordinates, not listview
# view coordinates
my ($ix, $iy, undef, undef) = $control->GetItemRect($i, LVIR_SELECTBOUNDS);
print "\tIcon for item $i at ($ix, $iy) - client coordinates\n" if $DEBUG;
# convert to listview coordinates
($ix, $iy) = ($ix + $vox, $iy + $voy);
print "\tIcon for item $i at ($ix, $iy) - listview view coordinates\n" if $DEBUG;
# create a temporary drag image for the item
# NOTE: scoping of $tmp_imagelist is important so that destructors get called
# NOTE: it really doesn't matter where we create this temporary image, as we never show it
my $tmp_imagelist = $control->CreateDragImage($i, $ix, $iy);
if(defined $dimagelist) {
# Merge the existing drag image with the image for the item we are adding in this loop
# NOTE: re-assinging a new imagelist to $dimagelist causes the ref count of the old one to go
# to zero, so it's destructor gets called impicitly.
$dimagelist = Win32::GUI::ImageList::Merge($dimagelist, 0, 0, $ix - $dix, $iy - $diy, $tmp_imagelist);
# maintain the top left corner of the drag image (view coordinates)
if($ix < $dix) { $dix = $ix; }
if($iy < $diy) { $diy = $iy; }
}
else {
# initialise the drag image
$dimagelist = $tmp_imagelist;
# initialise the top left corner of the drag image (view coordinates)
$dix = $ix;
$diy = $iy;
}
}
# Temporarily change the cursor to the drag cursor
# NOTE: Using SetCursor, the image gets changed immediatly
# without having to move cursor again ... but we must repeat
# the call on each mouse event, or it changes back (which is
# what we want on mouseup, of course)
Win32::GUI::SetCursor($curDrag);
# Restrict cursor to listview client area while dragging
# NOTE: could capture mouse (SetCapture), and then handle
# not moving the icon if mouseup is outside client area
my ($cl, $ct, $cr, $cb) = $control->GetClientRect();
my ($sl, $st) = $control->ClientToScreen($cl, $ct);
my ($sr, $sb) = $control->ClientToScreen($cr, $cb);
Win32::GUI::ClipCursor($sl, $st, $sr, $sb);
# Get the Cursor position
my ($csx, $csy) = Win32::GUI::GetCursorPos();
print "\tCursor at ($csx, $csy) - screen coordinates\n" if $DEBUG;
my ($ccx, $ccy) = $control->ScreenToClient($csx, $csy);
print "\tCursor at ($ccx, $ccy) - client coordinates\n" if $DEBUG;
# Convert cursor position into listview view coordinates
my ($cvx, $cvy) = ($ccx + $vox, $ccy + $voy);
print "\tCursor at ($cvx, $cvy) - listview view coordinates\n" if $DEBUG;
# Offset of cursor from where we draw the image. The Hotspot.
my $offset_hx = $dragInfo->{cursor_start_x} - $dix;
my $offset_hy = $dragInfo->{cursor_start_y} - $diy;
print "\tHotspot offset ($offset_hx, $offset_hy)\n" if $DEBUG;
# Create the temporary drag image
Win32::GUI::ImageList::BeginDrag($dimagelist, 0, $offset_hx, $offset_hy);
# Start dragging: lock updates to window and display drag image
# NOTE: window coordinates not client coordinates
Win32::GUI::ImageList::DragEnter( $control, $control->ClientToWindow($ccx, $ccy));
# We're dragging
$dragInfo->{dragging} = 1;
return 0; # we processed the message, so don't pass it on
}
######################################################################
# Called on mouse move events - when dragging, move the drag image
sub drag
{
my($control, $x, $y) = @_;
# If dragging ...
if($dragInfo->{dragging}) {
# Maintain the drag cursor
Win32::GUI::SetCursor($curDrag);
# Move the drag image
# NOTE: window coordinates not client coorinates
Win32::GUI::ImageList::DragMove($control->ClientToWindow($x, $y));
return 0; # we processed the message, so don't pass it on
}
return 1; # we didn't process the message, so pass to default handler
}
######################################################################
# Called on mouse up events - when dragging, remove the drag image
# and move the dragged items to their new positions
sub endDrag
{
my($control, $x, $y) = @_;
# If dragging ...
if($dragInfo->{dragging}) {
# Convert client coordinates of mouse to view coordinates, and
# calculate offset from initial cursor position
my ($vox, $voy) = $control->GetOrigin();
($vox, $voy) = (0,0) if not defined $vox; # GetOrigin returns undef for list and report views
my $move_x = $vox + $x - $dragInfo->{cursor_start_x};
my $move_y = $voy + $y - $dragInfo->{cursor_start_y};
# re-position each selected item
for my $i ($control->SelectedItems()) {
my($ox, $oy) = $control->GetItemPosition($i);
$control->ItemPosition($i, $ox + $move_x, $oy + $move_y);
}
print "Ending Drag ($x, $y) - client coordinates\n" if $DEBUG;
# unlock window and hide drag image
Win32::GUI::ImageList::DragLeave($control);
# end the drag, destroying the temporary drag image
Win32::GUI::ImageList::EndDrag();
# free the cursor from the client area
Win32::GUI::ClipCursor();
$dragInfo->{dragging} = 0; # not dragging any more
return 0; # we processed the message, so don't pass it on
}
return 1; # we didn't process the message, so pass to default handler
}
######################################################################
# main window resize handler
sub resize
{
my $self = shift;
$lv->Resize($self->ScaleWidth(), $self->ScaleHeight());
return 1;
}
######################################################################
# WM_CONTEXTMENU handler: Called on right mouse up, keyboard context
# menu key and shift-F10
sub lvPopup
{
my ($self, $wparam, $lparam, $type, $msgcode) = @_;
# if it isn't the event we are expecting, ignore it
return if($type != 0);
return if($msgcode != WM_CONTEXTMENU);
print "Context menu called\n" if $DEBUG;
my $hwnd = $wparam; # handle to the window clicked in
# don't process if it's not in our window (i.e. over a child window)
return if($hwnd != $self->{-handle});
my $x = $lparam & 0xFFFF; # in screen coordinates
my $y = $lparam >> 16; # in screen coordinates
# convert to signed values to cope with multiple monitors
# where screen coordinates can be negtive
if($x > 32767) { $x -= 65536; }
if($y > 32767) { $y -= 65536; }
my $menu; # which menu we'll display
if(($x == -1) and ($y == -1)) {
# One of Shift-F10 or VK_APP pressed
# Our decision what to do ...
# if no selected items, we'll display general menu at 0,0
# if selected items, ensure first selected item is
# visible and draw menu centered on it.
my $selected_items = $self->GetSelectedCount();
if($selected_items == 0) {
$x=0;
$y=0;
$menu=$Menus->{General};
}
else {
my $item = ($self->SelectedItems())[0];
$self->EnsureVisible($item);
# get top left of icon, in view coordinates
($x, $y) = $self->GetItemPosition($item);
# convert view coordinates to client coordinates
my ($vox, $voy) = $self->GetOrigin();
($x, $y) = ($x - $vox, $y - $voy);
# offset the menu from the top left of the icon
$x += 20;
$y += 20;
$menu=$Menus->{Item};
}
}
else {
# if mouse over an item, select that item (other items
# get deselected) and display item menu. If not over
# an item, show general menu
($x, $y) = $self->ScreenToClient($x, $y);
my $item = $self->HitTest($x, $y);
if($item == -1) {
$menu=$Menus->{General};
}
else {
$menu=$Menus->{Item};
}
}
# disable the edit name item if more than one item selected
if($self->GetSelectedCount() > 1) {
$Menus->{EditLabel}->Enabled(0);
}
else {
$Menus->{EditLabel}->Enabled(1);
}
# Display and process the menu (screen co-ordinates)
$mw->TrackPopupMenu(
$menu,
$self->ClientToScreen($x, $y),
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, # right-click menus should allow right selection
);
return 0; # don't pass on as we handled it
}
######################################################################
# Menu item processing functions
######################################################################
######################################################################
# Selects all items in the listview
sub select_all
{
my $self = shift;
print "Got Popup Menu SELECT ALL command\n" if $DEBUG;
$self->SelectAll();
return 0;
}
######################################################################
# Deselects all items in the listview
sub deselect_all
{
my $self = shift;
print "Got Popup Menu DESELECT ALL command\n" if $DEBUG;
$self->DeselectAll();
return 0;
}
######################################################################
# Arrange all the icons
sub arrange
{
my $self = shift;
print "Got Popup Menu ARRANGE command\n" if $DEBUG;
$self->Arrange();
return 0;
}
######################################################################
# Edit the text label
# See also BeginEdit and EndEdit listview events
sub edit_label
{
my $self = shift;
my $item = ($self->SelectedItems())[0];
print "Got Popup Menu EDIT LABEL command for Item $item\n" if $DEBUG;
$self->EditLabel($item);
return 0;
}
######################################################################
# Change the icon
sub change_icon
{
my $self = shift;
for my $item ($self->SelectedItems()) {
print "Got Popup Menu CHANGE ICON command for Item $item\n" if $DEBUG;
my %info = $self->GetItem($item);
my $image = $info{-image};
$self->ChangeItem(
-item => $item,
-image => not $image,
);
$self->Update($item);
}
return 0;
}
######################################################################
# Invert the selection
sub invert_sel
{
my $self = shift;
print "Got Popup Menu INVERT SELECCTION command\n" if $DEBUG;
my @items = $self->SelectedItems();
$self->SelectAll();
for my $item (@items) {
$self->Deselect($item);
}
return 0;
}
######################################################################
# change the view type
sub change_view
{
my $self = shift;
my $type = shift;
$self->View($type); # set view type
$self->Arrange();
return 0;
}
######################################################################
# Helper function to convert client coordinates to window
# coordinates
# Takes a 2 element list in client coordinates as input, and returns
# a 2 element list in window coordinates
sub Win32::GUI::ClientToWindow
{
my $win = shift;
my $x = shift;
my $y = shift;
my ($wl, $wt, undef, undef) = $win->GetWindowRect();
my ($cl, $ct, undef, undef) = $win->GetAbsClientRect();
return ($x + $cl - $wl,
$y + $ct - $wt);
}
######################################################################
# Function to create and return the imagelists that we will use
sub CreateImageLists
{
my $bmpMobile = new Win32::GUI::BitmapInline( q(
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
) );
my $bmpMobileMask = new Win32::GUI::BitmapInline( q(
Qk2+AAAAAAAAAD4AAAAoAAAAIAAAACAAAAABAAEAAAAAAIAAAAAjCwAAIwsAAAIAAAACAAAAAAAA
AP///wD//////+A////gB///4AP//8AD///AA///wAP//8AD///AA///wAP//8AD///AA///wAP/
/8AD///AA///wAP//8AD///AA///wAP//8AD///AA///wAP//8AD///AA///wAP//8AD///AB///
4f///+H////h////4f////H//w==
) );
my $bmpMobileSmall = new Win32::GUI::BitmapInline( q(
Qk02AwAAAAAAADYAAAAoAAAAEAAAABAAAAABABgAAAAAAAADAAATCwAAEwsAAAAAAAAAAAAAAAAH
AxMaAAAGAAAEAAUIBxQWAAEBAQUGBQABEwIGFQADHAEKDwAHAgAGAAAHAAAAAAQLAAEHETc5IE5P
FUZEAB8dKFJRFzk4MEdJFyYpOEFFIisvKjg+AAIIAA4VAAAAAAAGFTs9J3t3GId/DIN6D4R7JI6H
FXVvLIB+MH98Ln16NoWCKHd0CEZGAAMGAAAAAAIJFjw+j/PtQ83CDKOZAJGIdP/9Gp+cgPv5JZqZ
if77IJGND3lzAE9MAAIGAAAABQAEKEFDr///be7nOtDKACMfM83MABETUNveACMmRsHDYNDQMJGP
ACwsBQ4SAAAABAADJDc6vf/+lv//WfDtKc/OdP//RNXdZu76Q8rShf//Vs3PLn+CDTY5AAAEAAAA
AA0MIzg62///nfH2YP/9ABQVUOLuABEjfvX/AAoZQd3iB4qNP3Z/OkVNAgAGAAAAAAQBAAgIFy42
x///Z+3xT/X6cP//WOj6dv//RNHgeP//B3mAGz5LAAAHAAAEAAAAAAUBAA0MAAAIHUBNp/n/AAsW
U///ABQdMPT+ABAbX9blADZFAAANCAcRAAEGAAAAAAsGED89ADEyAD1Fwf//ju38QtrlRv3/Itnj
OdPeFXSDB0RSDEFLBC0wAAIEAAAAGTs6jM/KKKugAIJ8ADc/K3B/TqOzJoWVGXuNHnuKAC88JoGI
AIB6MauhBzg2AAAAESoswv//WObZBqSYFIKCAEBJADZEADtLCktaACs2NpacHJmXROnca/fqADQx
AAAANEJI0vn7r///fPbuc/z0effyrP//rfn/nPD1m///a//5W/vvFJ+UiurkGDc6AAAAAAEIJDg9
BiwwneHgoP//k/32uv//rfHwk9/eqP//OMK2AHVpAFBLCTo8AAAGAAAAAAAHAAAHBwAGSUBKDxoe
LkNFITg6JENCG0NCAC4sB0I+EkNBAAYLAAAHAAAHAAAAAAAHAQAKHgAGKQAGIAAIFgEJAgABAAMD
AAUDAAQBABESAAADDgAGEQAJAwIMAAAA
) );
my $bmpMobileMaskSmall = new Win32::GUI::BitmapInline( q(
Qk1+AAAAAAAAAD4AAAAoAAAAEAAAABAAAAABAAEAAAAAAEAAAAAjCwAAIwsAAAIAAAACAAAA////
AAAAAAAAAAAAP/wAAH/8AAB//AAAf/wAAH/8AAB//AAAH/gAAB/wAAB/+AAAf/wAAH/8AAB//AAA
H/wAAAAAAAAAAAAA
) );
my $bmpPhone = new Win32::GUI::BitmapInline( q(
Qk02DAAAAAAAADYAAAAoAAAAIAAAACAAAAABABgAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAA////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////8/Pzy8vLy8vL1tbW+fn5////////////////////////////////////////
////////////////////////////////////////////////////////////8/Pzy8vLp6etTU1/
TU1tYWF0ubm61tbW+fn5////////////////////////////////////////////////////////
////////////////////////////8/Pzy8vLrKyxVlaIR0ecCwvVCwuMHBx7Tk5ybGx8vLy91tbW
+fn5////////////////////////////////////////////////////////////////////8/Pz
y8vLp6etTU2FOzugAAD/AAD/AADjAACRAACEAACEEBB+RERsYWF0ubm61tbW+fn5////////////
////////////////////////////////////////8/Pzy8vLrKyxVlaIR0ecCwvtCAjxAAD/AAD/
AADjAACRAACEAACEAgKDCQmAHBx7Tk5ybGx8vLy91tbW+fn5////////////////////////////
////////8/Pzy8vLp6etTU2FOzugAAD/AAD/AAD/AAD/AAD/DAz8KyvcBgaQAACEAACEAACEAACE
AACEAACEEBB+RERsYWF0ubm61tbW+fn5////////////////////////y8vLrKyxVlaIR0ecCwvt
CAjxAAD/AAD/AAD/DAz8ODj1XV3vsLDHGRmNAACEAACEAACEAACEAACEAACEAgKDCQmAHBx7Tk5y
bGx8vLy91tbW+fn5////////////////Xl5qPj6cAAD/AAD/AAD/AAD/AAD/DAz8ODj1ZGTu///W
8vLYmprQFhagAACEAACEAACEAACEAACEAACEAACEAACEAACEBASCJiZ2Wlplb29vurq6y8vL1tbW
////////T0+BEhLiAAD/AAD/AAD/DAz8ODj1XV3v4uLa29vbxsbeoKDkFhb4AwPfAACYAACGAACE
AACEAACEAACEAACEAACEBASCISF4VVVtTk6BTk5/VlZyVlZwbGx81tbW+fn5TU2FCwvtAAD/DAz8
ODj1ZGTu///W8vLYxsbfmprlAAD/AAD/AAD/AAD/AADpAACjAACEAACEAACEAACEAACEAACEFRV8
UlJuOzugCAjxAADjAACRAACEEBB+YWF0ubm6TU2FFxfrODj1XV3v4uLa29vbxsbeoKDkHBz6FRX1
AADdAADVAAD/AAD/AAD7AADgAACYAACGAACEAACEAACEBASCISF4NzeJCAjrAQHkBATMEhKIFRV8
EhJ9ISF6YGBsTU2FQ0Pk///W8vLYxsbfmprlAAD/AAD4AADdDQ2/ODh/KytiAADpAAD7AAD/AAD/
AADpAACjAACEAACEAACEFRV8TU1qCwuUAADUAACmEBCTRERwTU1qQEBtJiZ2WlplYWGFR0fNxsbe
oKDkHBz6FRX1AADdDAzBOTmRVFRxra20lZWjAACdAADMAAD/AAD/AAD7AADgAACYAACGAACEFRV8
UVFoGRmEAAC7AADpAgLYCQmMCwuAFhZ7SEhqX19k1dXVbGyMEBDkAgL7AAD/DAznODh/V1dbyMjA
qamvLS2Bi4ubODh/KytiAADpAAD7AAD/AAD/AADpAACjAACEFRV8Xl5kPj6JAAD/AAD/AADjAACR
AACEAACEFRV8V1dm+fn5xsbHWlqRGxvWAAD/JSX1qanSioq7PT2HhISVPj6DYGBpra20lZWjAACd
AADMAAD/AAD/AAD7AADgAACYFRV/T09pEhKYAAD/AAD/AADpAACjAACEAACEFRV8V1dm////////
1tbWbGyLEBDkAgL7AAD/DAznODh/V1dbyMjAqamvLS2Bi4ubODh/KytiAADpAAD7AAD/AAD/AADp
FRWcTU1qCwuaAAD/AAD/DAz8MjLhODiWKyuSFRV8V1dm////////+fn5xsbHWlqRGxvWAAD/JSX1
qanSioq7PT2HhISVPj6DYGBpqam9g4O/AAC+AAD1AAD/AAD4AADgFRW9TU1qCwuaAAD/DAz8UVHx
nZ3iqanVkJDHQUGKXl5o////////////////1tbWbGyLEBDkAgL7AAD/DAznODh/V1dbxsbJmprN
AAC0AAD0AAD/BAT3EBDkAgLfAACEFRV8TU1qCwuaAAD/ODj1xsbfHBz6AAD/MDDvv7+nfHx6////
////////////7e3toKCjSEiLFxfYAAD/JSX1qanSiorBHBy5FRXvAAD0BAT1FRXcIyPFUFCQLy/N
AACEFRV8TU1wCwutDAz8UVHxmprlFRX7BAT3LS3Fjo6M09PT////////////8/Pzra2seXl+VFR4
VlZyEBDkAgL7AAD/AAD/AAD4AADmBATiHx/DTU1qUVFohYV8wcG6MDCQJSV7OzuKFRXsV1fwioro
AAD/BAT3LCy/gICO////////////////////0dHRhIR8sLC9NjakaWlHNzeQFRXZAAD/AAD/AADm
AACdExOLPDx5CwuAGRmBbGyRxcWzo6OjT099QECoUlLmioroJSX4BAT3JyfGgICO2dnZ////////
////////////y8vLfX12rq6lTU2FOzuEEBB+ODiGEBDkDg74KyvcBgaQFRV8QUFzAACfAACzEBDk
UFCQdHSBYGCixsbfmprlBAT3ExPgLCy/gICO////////////////////////////y8vLbm5rcXGa
CwvtCAjbAgKXFRWCNzeQR0fQvLzLQ0OXISF+NTWcAADxDAzxOjrxW1vhsrLSi4vcISHyKCjcKirD
Y2OJgICO2dnZ////////////////////////////1tbWhYWAqam9Kyv3Bgb9AADpAACjEBB+Y2N/
3Ny8vLyvSEieOjrpODj1V1fwxsbfmprlBAT3ExPgLCy/a2t8iIiI6enp////////////////////
////////////////+fn5xMTEj4+NoaHMOjrxAAD7DAzeOjqVVFSQlpaJg4OdWVnjnp7jqanjj4/g
MTHXKyvYKirDY2OJgICO09PT6enp/Pz8////////////////////////////////////////////
1tbWhYWAoaG4EBDkLS3zxsbfxsbfxsbfxsbfn5/eKSncFRXcLCy/dHR0dHR0iIiI6enp////////
////////////////////////////////////////////////////+fn5xMTEgoKEWlqRJibOMTHX
MTHXMTHXMTHXPz+/ZmaIa2uBgICO5OTk5OTk6enp/Pz8////////////////////////////////
////////////////////////////////////////1tbWfX19dHR0dHR0dHR0dHR0iIiI6enp////
////////////////////////////////////////////////////////////////////////////
////////////////+fn55ubm5OTk5OTk5OTk5OTk6enp/Pz8////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
) );
my $bmpPhoneMask = new Win32::GUI::BitmapInline( q(
Qk2+AAAAAAAAAD4AAAAoAAAAIAAAACAAAAABAAEAAAAAAIAAAAATCwAAEwsAAAIAAAACAAAAAAAA
AP///wD///////P////A////AD///AAH//AAA//AAAB/AAAAHwAAAAMAAAABAAAAAAAAAAAAAAAA
AAAAAAAAAACAAAAAwAAAAOAAAADwAAAA+AAAAPAAAAPgAAAD4AAAD+AAAB/gAAB/8AAA//gAB//8
AD///wH//////////////////w==
) );
my $bmpPhoneSmall = new Win32::GUI::BitmapInline( q(
Qk02AwAAAAAAADYAAAAoAAAAEAAAABAAAAABABgAAAAAAAADAAATCwAAEwsAAAAAAAAAAAAA//v/
/v3/8fX2+v//4ezq9P//8v//8///6ff29P//9v//7vb2+/7//fz/+vn///7///v//fr/7+//8PL/
9Pv/8fv/7f3/5/f/7fz/7ff/8/v/8vb/9Pf/+/v/+Pf///7///r/T0hpOjNgVk6DSkV8SEp6NDlm
R0x5Q0d3QT52S0Z9VE59UU1wamp8+/7//f//6+b7h3yuemuva1ytaV6ud3K3dHWydHWyXFufeXDB
dGe7dWmxRj9yJyc/+v3//f//+vb/saPjh3TLrZn8iHrYhoHMjo7OiYjKkIzYl4rslIPqrp/7c2mv
WVp87vL9/f//8vH/pprce2nEiXbdh3ja39v/e3q+0NH/hIHR1Mf/eGjTiHrahn7FUlR29v3/+///
7vP/9O//in7Kb2K+iH3ZtbH9k5PZsbH3rar5ppv7joHji4PWODZxsLvR8/7/+v//5e738/T/rqnm
amGxd27E2dT/nJrmzsv/v7v/z8b/e3PKfHi/ZWmZ5vL/8///+v7/8v7/8/f/6en/ranraWOywrv/
jYTepZ75l5Hqp6L3ammzQEJ87PX/3uz/8f3/+vz/Ki9IMzhZaWmXz83/kY7TxsD/pZ/xxr//zcn/
zMr/dne7g4W/foO0Rkx1JClI6+r+i4XGrajlKCVdkI/Hp6jgdXawhYXBkZDOamqqY2OjXFudq6nv
ZmKugHrMR0KHbGiLTD6WenC9Qzx/lZLK0tX/P0NsoKfO7/P/3+T/e3y0YF+jsav8bmPDdGbQTECY
k422fGrHfm7FU0eTQDp17O7/4Of/5fH/7PX/6vL/2tv/qqbtfXLOcGHKi3nqLR55sazTmI/SfXK7
q6DpTkaFGhdIU1dzbniKbneLYWWIZmKdXlajkITejIHefnTOS0SH9vX/8fr/sbDalo/MmI3TiX/B
h4O0R0dvT054Pjtycmi0h33Qg3rKe3i2pq/RzNbn9v7/6fzt8/j/8+7/7eH/7uL/zcX/4Nv/19L/
7OT/0MP/2Mr/4tv/7/H/3vD38f/79P/8
) );
my $bmpPhoneMaskSmall = new Win32::GUI::BitmapInline( q(
Qk1+AAAAAAAAAD4AAAAoAAAAEAAAABAAAAABAAEAAAAAAEAAAAAjCwAAIwsAAAIAAAACAAAAAAAA
AP///wD//wAA//8AAIADAACAAwAAgAMAAIADAADAAwAAwAcAAMAPAAAAAQAAAAAAAAAAAAAAAAAA
AAEAAIABAADgAwAA
) );
# Cretae the NORMAL imagelist (large icons)
my $ilLarge = Win32::GUI::ImageList->new(32, 32, ILC_COLOR|ILC_COLOR24|ILC_MASK, 2, 0);
$ilLarge->Add($bmpMobile, $bmpMobileMask);
$ilLarge->Add($bmpPhone, $bmpPhoneMask);
# Cretae the SMALL imagelist (small icons)
my $ilSmall= Win32::GUI::ImageList->new(16, 16, ILC_COLOR|ILC_COLOR24|ILC_MASK, 2, 0);
$ilSmall->Add($bmpMobileSmall, $bmpMobileMaskSmall);
$ilSmall->Add($bmpPhoneSmall, $bmpPhoneMaskSmall);
return ($ilLarge, $ilSmall);
}