#! /usr/bin/perl -w

use strict;
use Gtk3 '-init';
use Glib qw/TRUE FALSE/;
use Gtk3::SimpleList;
use Try::Tiny;

#Declare our columns
use constant C_MARKUP               => 0;
use constant C_PIXBUF               => 1;

#Declare our IDENDTIFIER ID's
use constant ID_ICONVIEW            => 48;
use constant ID_LABEL               => 49;
use constant ID_URI                 => 50;

#standard window creation, placement, and signal connecting
my $window = Gtk3::Window->new('toplevel');
$window->signal_connect('delete_event' => sub { Gtk3->main_quit; });
$window->set_border_width(5);
$window->set_position('center_always');

#add and show the vbox
$window->add(&ret_vbox);
$window->show();

#our main event-loop
Gtk3->main();

sub ret_vbox {

    my $vbox = Gtk3::VBox->new(FALSE,5);
    my $h_paned = Gtk3::HPaned->new();

    my $v_paned = Gtk3::VPaned->new();
    #get the iconview
    $v_paned->pack1(create_iconview(),TRUE,FALSE);

    #get the simple list where everything will be dropped into
    $v_paned->pack2(create_simple_list(),TRUE,FALSE);

    $h_paned->pack1($v_paned,TRUE,FALSE);

    #create an eventbox to accept drag actions
    my $event_box = Gtk3::EventBox->new();
    my $label_drag_me = Gtk3::Label->new("Now Stanley,\nDO NOT drag this item");
    $event_box->add($label_drag_me);

    #Try and convince the user otherwise
    $event_box->set_tooltip_text (
         'No way! You have to drag it at least once!'.
         'Drag it, and drop it into the bottom list'
    );

    #Setting up the Gtk3::Event Box instead of the Gtk3::Label, enabling it as
    #a drag source
    my $dnd_source = Gtk3::TargetEntry->new(
        'text/plain',    # some string representing the drag type
        [],                #flags
        ID_LABEL,          # some app-defined integer identifier
    );
    $event_box->drag_source_set( 'button1_mask', [$dnd_source], [ 'copy' ] );

    my $text_to_drag = '<span foreground="red" size="x-large">"Well there\'s another nice mess you\'ve gotten me into."</span>';

    #set up the data which needs to be fed to the drag destination (drop)
    $event_box->signal_connect ('drag-data-get' => \&source_drag_data_get,$text_to_drag );

    $h_paned->pack2($event_box,TRUE,FALSE);

$vbox->add($h_paned);
$vbox->show_all();
return $vbox;
}

sub create_iconview {
#---------------------------------------------------
#Creates an Iconview in a ScrolledWindow. This -----
#Iconview has the ability to drag items off it  -----
#---------------------------------------------------

    my $icon_string= undef;
    my $tree_model = create_iconview_model();

    my $icon_view = Gtk3::IconView->new_with_model($tree_model);
    $icon_view->set_markup_column(C_MARKUP);
    $icon_view->set_pixbuf_column(C_PIXBUF);

    #Enable the Gtk3::IconView as a drag source
    my $dnd_source = Gtk3::TargetEntry->new(
        'Glib::Scalar',    # some string representing the drag type
        [],                #flags
        ID_ICONVIEW,          # some app-defined integer identifier
    );
    $icon_view->drag_source_set( ['button1_mask', 'button3_mask'], [$dnd_source], [ 'copy' ] );

    #This is a nice to have. It changes the drag icon to that of the
    #icon which are now selected and dragged (single selection mode)
    $icon_view->signal_connect('drag-begin' => sub {
        $icon_view->selected_foreach ( sub{

                my $iter =$tree_model->get_iter($_[1]);
                #set the text and pixbuf
                my $icon_pixbuf = $tree_model->get_value($iter,C_PIXBUF);
                $icon_string = $tree_model->get_value($iter,C_MARKUP);
                $icon_view->drag_source_set_icon_pixbuf ($icon_pixbuf);
        } );
    });

    #set up the data which needs to be fed to the drag destination (drop)
    $icon_view->signal_connect ('drag-data-get' => sub { source_drag_data_get(@_,$icon_string) } );

    #Standard scrolledwindow to allow growth
    my $sw = Gtk3::ScrolledWindow->new(undef,undef);
    $sw->set_policy('never','automatic');
    $sw->add($icon_view);
    $sw->set_border_width(6);
    $sw->set_size_request(600,150);
    return $sw;
}

sub create_iconview_model {
#----------------------------------------------------
#The Iconview needs a Gtk3::Treemodel implementation-
#containing at least a Glib::String and -------------
#Gtk3::Gdk::Pixbuf type. The first is used for the --
#text of the icon, and the last for the icon self----
#Gtk3::ListStore is ideal for this ------------------
#----------------------------------------------------

    my $list_store = Gtk3::ListStore->new(qw/Glib::String Gtk3::Gdk::Pixbuf/);

    #******************************************************
    #we populate the Gtk3::ListStore with Gtk3::Stock icons
    #******************************************************

    my $icon_factory = Gtk3::IconFactory->new();
    my @ids = Gtk3::Stock::list_ids;
    for my $val(sort @ids){
        #get the iconset from the icon_factory
        #try and extract the icon from it
        my $pixbuf;
        try {
            $pixbuf = Gtk3::IconTheme::get_default->load_icon($val, 64, [])
        }
        catch {
            print "$val not in theme\n";
        };

        #if there was a valid icon in the iconset, add it
        if( defined $pixbuf ){

            my $iter = $list_store->append;
            $list_store->set (
                        $iter,
                        C_MARKUP, "<b>$val</b>",
                        C_PIXBUF, $pixbuf,
             );

        }
    }

    return $list_store;
}

sub create_simple_list {
#---------------------------------------------------
#Creates a simple list with pixbuf and markup  -----
#columns make this list the drop target for various-
#drag sources --------------------------------------
#---------------------------------------------------

    my $slist = Gtk3::SimpleList->new ('' => 'pixbuf', ''  => 'markup');
    $slist->set_rules_hint(TRUE);
    $slist->set_headers_visible(FALSE);

     #Also suggest to try Nautilus
     $slist->set_tooltip_text (
            'Drag a few files from Nautilus '.
            'and drop it here'
            );

    #Create a target table to receive drops
    my $target_table = [
         Gtk3::TargetEntry->new(
                                'Glib::Scalar',    # some string representing the drag type
                                [],                #flags
                                ID_ICONVIEW,          # some app-defined integer identifier
                               ),
         Gtk3::TargetEntry->new(
                                'text/uri-list',    # some string representing the drag type
                                [],                #flags
                                ID_URI,          # some app-defined integer identifier
                               ),
         Gtk3::TargetEntry->new(
                                'text/plain',    # some string representing the drag type
                                [],                #flags
                                ID_LABEL,          # some app-defined integer identifier
                               ),
    ];

    #make this the drag destination (drop) for various drag sources
    $slist->drag_dest_set( [ 'all' ], $target_table, [ 'copy' ] );

    #do a callback as soon as drag data is received
    $slist->signal_connect ('drag-data-received' => \&target_drag_data_received,$slist );

    #Standard scrolledwindow to allow growth
    my $sw = Gtk3::ScrolledWindow->new(undef,undef);
    $sw->set_policy('never','automatic');
    $sw->add($slist);
    $sw->set_border_width(6);
    $sw->set_size_request(600,150);
    return $sw;
}

sub target_drag_data_received {
#---------------------------------------------------
#Extract the data which was set up during the  -----
#'drag-data-get' event which fired just before -----
#the 'drag-data-received' event. Also checks which--
#source supplied the data, and handle accordingly----
#---------------------------------------------------

    my ($widget, $context, $x, $y, $data, $info, $time,$slist) = @_;

    if ($info eq ID_LABEL){
        my $pixbuf = Gtk3::IconTheme::get_default->load_icon('gtk-no', 64, []);
        use Data::Dumper;
        print Dumper($data->get_data);
        push @{$slist->{data}}, [ $pixbuf, $data->get_data ];
    }

    if ($info eq ID_URI){
        my $pixbuf = Gtk3::IconTheme::get_default->load_icon('gtk-yes', 64, []);
        foreach ($data->get_uris){
            push @{$slist->{data}}, 
                    [ $pixbuf, '<span foreground="forest green" size="x-small">'.$_.'</span>' ];
        }
    }

    if ($info eq ID_ICONVIEW){
        my $no_markup = $data->get_data;
        $no_markup =~ s/<[^>]*>//g;
        my $iconset = Gtk3::Stock::lookup($no_markup);
        my $pixbuf = $iconset->render_icon(Gtk3::Style->new(),'none','normal','menu',undef);
        push @{$slist->{data}}, [ $pixbuf, $data->get_data ];
    }

#    $context->finish (0, 0, $time);
}

sub source_drag_data_get {
#---------------------------------------------------
#This sets up the data of the drag source. It is ---
#required before the 'drag-data-received' event ----
#fires which can be used to extract this data ------
#---------------------------------------------------

    my ($widget, $context, $data, $info, $time,$string) = @_;
    use Data::Dumper;
    print Dumper($widget, $context, $data, $info, $time,$string);
    $data->set_text($string,-1);
}
